public function markupText($text, $children) { $engine = $this->getEngine(); $text = trim($text); $text = $this->applyRules($text); if ($engine->isTextMode()) { if (!$this->getEngine()->getConfig('preserve-linebreaks')) { $text = preg_replace('/ *\\n */', ' ', $text); } return $text; } if ($engine->getConfig('preserve-linebreaks')) { $text = phutil_escape_html_newlines($text); } if (!strlen($text)) { return null; } $default_attributes = $engine->getConfig('default.p.attributes'); if ($default_attributes) { $attributes = $default_attributes; } else { $attributes = array(); } return phutil_tag('p', $attributes, $text); }
public function renderForMail() { $diff = $this->buildDiff(); $old_styles = array('padding: 0 2px;', 'color: #802b2b;', 'background: rgba(251, 175, 175, .7);'); $old_styles = implode(' ', $old_styles); $new_styles = array('padding: 0 2px;', 'color: #3e6d35;', 'background: rgba(151, 234, 151, .6);'); $new_styles = implode(' ', $new_styles); $omit_styles = array('padding: 8px 0;'); $omit_styles = implode(' ', $omit_styles); $result = array(); foreach ($diff->getSummaryParts() as $part) { $type = $part['type']; $text = $part['text']; switch ($type) { case '.': $result[] = phutil_tag('div', array('style' => $omit_styles), pht('...')); break; case '-': $result[] = phutil_tag('span', array('style' => $old_styles), $text); break; case '+': $result[] = phutil_tag('span', array('style' => $new_styles), $text); break; case '=': $result[] = $text; break; } } $styles = array('white-space: pre-wrap;', 'color: #74777D;'); // Beyond applying "pre-wrap", convert newlines to "<br />" explicitly // to improve behavior in clients like Airmail. $result = phutil_escape_html_newlines($result); return phutil_tag('div', array('style' => implode(' ', $styles)), $result); }
public function processRequest() { $request = $this->getRequest(); $viewer = $request->getUser(); $signature = id(new LegalpadDocumentSignatureQuery())->setViewer($viewer)->withIDs(array($this->id))->executeOne(); if (!$signature) { return new Aphront404Response(); } // NOTE: In order to see signature details (which include the relatively // internal-feeling "notes" field) you must be able to edit the document. // Essentially, this power is for document managers. Notably, this prevents // users from seeing notes about their own exemptions by guessing their // signature ID. This is purely a policy check. $document = id(new LegalpadDocumentQuery())->setViewer($viewer)->withIDs(array($signature->getDocument()->getID()))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne(); if (!$document) { return new Aphront404Response(); } $document_id = $signature->getDocument()->getID(); $next_uri = $this->getApplicationURI('signatures/' . $document_id . '/'); $data = $signature->getSignatureData(); $exemption_phid = $signature->getExemptionPHID(); $actor_phid = idx($data, 'actorPHID'); $handles = $this->loadViewerHandles(array($exemption_phid, $actor_phid)); $exemptor_handle = $handles[$exemption_phid]; $actor_handle = $handles[$actor_phid]; $form = id(new AphrontFormView())->setUser($viewer); if ($signature->getExemptionPHID()) { $form->appendChild(id(new AphrontFormMarkupControl())->setLabel(pht('Exemption By'))->setValue($exemptor_handle->renderLink()))->appendChild(id(new AphrontFormMarkupControl())->setLabel(pht('Notes'))->setValue(idx($data, 'notes'))); } $type_corporation = LegalpadDocument::SIGNATURE_TYPE_CORPORATION; if ($signature->getSignatureType() == $type_corporation) { $form->appendChild(id(new AphrontFormMarkupControl())->setLabel(pht('Signing User'))->setValue($actor_handle->renderLink()))->appendChild(id(new AphrontFormMarkupControl())->setLabel(pht('Company Name'))->setValue(idx($data, 'name')))->appendChild(id(new AphrontFormMarkupControl())->setLabel(pht('Address'))->setValue(phutil_escape_html_newlines(idx($data, 'address'))))->appendChild(id(new AphrontFormMarkupControl())->setLabel(pht('Contact Name'))->setValue(idx($data, 'contact.name')))->appendChild(id(new AphrontFormMarkupControl())->setLabel(pht('Contact Email'))->setValue(phutil_tag('a', array('href' => 'mailto:' . idx($data, 'email')), idx($data, 'email')))); } return $this->newDialog()->setTitle(pht('Signature Details'))->setWidth(AphrontDialogView::WIDTH_FORM)->appendChild($form->buildLayoutView())->addCancelButton($next_uri, pht('Close')); }
public function apply($text) { if ($this->getEngine()->isTextMode()) { return $text; } return phutil_escape_html_newlines($text); }
public function getBodyForFeed(PhabricatorFeedStory $story) { $new = $this->getNewValue(); $body = null; switch ($this->getTransactionType()) { case self::TYPE_CONTENT: return phutil_escape_html_newlines(id(new PhutilUTF8StringTruncator())->setMaximumGlyphs(128)->truncateString($new)); break; } return parent::getBodyForFeed($story); }
protected function getResponseBody() { $ex = $this->exception; if ($ex instanceof AphrontUsageException) { $title = $ex->getTitle(); } else { $title = get_class($ex); } $body = $ex->getMessage(); $body = phutil_escape_html_newlines($body); return phutil_tag('div', array('class' => 'unhandled-exception-detail'), array(phutil_tag('h1', array('class' => 'unhandled-exception-title'), $title), phutil_tag('div', array('class' => 'unhandled-exception-body'), $body))); }
protected function renderHarbormasterStatus(DifferentialDiff $diff, array $messages) { $colors = array(DifferentialLintStatus::LINT_NONE => 'grey', DifferentialLintStatus::LINT_OKAY => 'green', DifferentialLintStatus::LINT_WARN => 'yellow', DifferentialLintStatus::LINT_FAIL => 'red', DifferentialLintStatus::LINT_SKIP => 'blue', DifferentialLintStatus::LINT_AUTO_SKIP => 'blue'); $icon_color = idx($colors, $diff->getLintStatus(), 'grey'); $message = DifferentialRevisionUpdateHistoryView::getDiffLintMessage($diff); $excuse = $diff->getProperty('arc:lint-excuse'); if (strlen($excuse)) { $excuse = array(phutil_tag('strong', array(), pht('Excuse:')), ' ', phutil_escape_html_newlines($excuse)); } $status = id(new PHUIStatusListView())->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_STAR, $icon_color)->setTarget($message)->setNote($excuse)); return $status; }
/** * Add a block of text with a section header. This is rendered like this: * * HEADER * Text is indented. * * @param string Header text. * @param string Section text. * @return this * @task compose */ public function addTextSection($header, $section) { if ($section instanceof PhabricatorMetaMTAMailSection) { $plaintext = $section->getPlaintext(); $html = $section->getHTML(); } else { $plaintext = $section; $html = phutil_escape_html_newlines(phutil_tag('div', array(), $section)); } $this->addPlaintextSection($header, $plaintext); $this->addHTMLSection($header, $html); return $this; }
public function processRequest() { try { $status = PhabricatorNotificationClient::getServerStatus(); $status = $this->renderServerStatus($status); } catch (Exception $ex) { $status = new AphrontErrorView(); $status->setTitle('Notification Server Issue'); $status->appendChild(hsprintf('Unable to determine server status. This probably means the server ' . 'is not in great shape. The specific issue encountered was:' . '<br />' . '<br />' . '<strong>%s</strong> %s', get_class($ex), phutil_escape_html_newlines($ex->getMessage()))); } $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Status')); return $this->buildApplicationPage(array($crumbs, $status), array('title' => pht('Notification Server Status'), 'device' => false)); }
public function markupText($text) { $text = trim($text); $text = $this->applyRules($text); if ($this->getEngine()->isTextMode()) { if (!$this->getEngine()->getConfig('preserve-linebreaks')) { $text = preg_replace('/ *\\n */', ' ', $text); } return $text; } if ($this->getEngine()->getConfig('preserve-linebreaks')) { $text = phutil_escape_html_newlines($text); } return phutil_tag('p', array(), $text); }
public function newTable() { $viewer = $this->getViewer(); $logs = $this->getLogs(); $show_sources = $this->getShowImportSources(); $rows = array(); foreach ($logs as $log) { $icon = $log->getDisplayIcon($viewer); $color = $log->getDisplayColor($viewer); $name = $log->getDisplayType($viewer); $description = $log->getDisplayDescription($viewer); $rows[] = array($log->getID(), $show_sources ? $viewer->renderHandle($log->getImport()->getPHID()) : null, id(new PHUIIconView())->setIcon($icon, $color), $name, phutil_escape_html_newlines($description), phabricator_datetime($log->getDateCreated(), $viewer)); } $table = id(new AphrontTableView($rows))->setHeaders(array(pht('ID'), pht('Source'), null, pht('Type'), pht('Message'), pht('Date')))->setColumnVisibility(array(true, $show_sources))->setColumnClasses(array('top', 'top', 'top', 'top pri', 'top wide', 'top')); return $table; }
public function render() { $readme_path = $this->getPath(); $readme_name = basename($readme_path); $interpreter = $this->getReadmeLanguage($readme_name); require_celerity_resource('diffusion-readme-css'); $content = $this->getContent(); $class = null; switch ($interpreter) { case 'remarkup': // TODO: This is sketchy, but make sure we hit the markup cache. $markup_object = id(new PhabricatorMarkupOneOff())->setEngineRuleset('diffusion-readme')->setContent($content); $markup_field = 'default'; $content = id(new PhabricatorMarkupEngine())->setViewer($this->getUser())->addObject($markup_object, $markup_field)->process()->getOutput($markup_object, $markup_field); $engine = $markup_object->newMarkupEngine($markup_field); $toc = PhutilRemarkupHeaderBlockRule::renderTableOfContents($engine); if ($toc) { $toc = phutil_tag_div('phabricator-remarkup-toc', array(phutil_tag_div('phabricator-remarkup-toc-header', pht('Table of Contents')), $toc)); $content = array($toc, $content); } $readme_content = $content; $class = null; break; case 'rainbow': $content = id(new PhutilRainbowSyntaxHighlighter())->getHighlightFuture($content)->resolve(); $readme_content = phutil_escape_html_newlines($content); require_celerity_resource('syntax-highlighting-css'); $class = 'remarkup-code ml'; break; default: case 'text': $readme_content = phutil_escape_html_newlines($content); $class = 'ml'; break; } $readme_content = phutil_tag_div($class, $readme_content); $header = id(new PHUIHeaderView())->setHeader($readme_name); $document = id(new PHUIDocumentViewPro())->setFluid(true)->appendChild($readme_content); return id(new PHUIObjectBoxView())->setHeader($header)->appendChild($document)->addClass('diffusion-readme-view'); }
protected function getResult(ConduitAPIRequest $request) { $drequest = $this->getDiffusionRequest(); $path_dicts = $request->getValue('paths', array()); $paths = array(); foreach ($path_dicts as $dict) { $paths[] = DiffusionRepositoryPath::newFromDictionary($dict); } $best = -1; $readme = ''; $best_render_type = 'plain'; foreach ($paths as $result_path) { $file_type = $result_path->getFileType(); if ($file_type != ArcanistDiffChangeType::FILE_NORMAL && $file_type != ArcanistDiffChangeType::FILE_TEXT) { // Skip directories, etc. continue; } $path = strtolower($result_path->getPath()); if ($path === 'readme') { $path .= '.remarkup'; } if (strncmp($path, 'readme.', 7) !== 0) { continue; } $priority = 0; switch (substr($path, 7)) { case 'remarkup': $priority = 100; $render_type = 'remarkup'; break; case 'rainbow': $priority = 90; $render_type = 'rainbow'; break; case 'md': $priority = 50; $render_type = 'remarkup'; break; case 'txt': $priority = 10; $render_type = 'plain'; break; default: $priority = 0; $render_type = 'plain'; break; } if ($priority > $best) { $best = $priority; $readme = $result_path; $best_render_type = $render_type; } } if (!$readme) { return ''; } $readme_request = DiffusionRequest::newFromDictionary(array('user' => $request->getUser(), 'repository' => $drequest->getRepository(), 'commit' => $drequest->getStableCommit(), 'path' => $readme->getFullPath())); $file_content = DiffusionFileContent::newFromConduit(DiffusionQuery::callConduitWithDiffusionRequest($request->getUser(), $readme_request, 'diffusion.filecontentquery', array('commit' => $drequest->getStableCommit(), 'path' => $readme->getFullPath(), 'needsBlame' => false))); $readme_content = $file_content->getCorpus(); switch ($best_render_type) { case 'plain': $readme_content = phutil_escape_html_newlines($readme_content); $class = null; break; case 'rainbow': $highlighter = new PhutilRainbowSyntaxHighlighter(); $readme_content = $highlighter->getHighlightFuture($readme_content)->resolve(); $readme_content = phutil_escape_html_newlines($readme_content); require_celerity_resource('syntax-highlighting-css'); $class = 'remarkup-code'; break; case 'remarkup': // TODO: This is sketchy, but make sure we hit the markup cache. $markup_object = id(new PhabricatorMarkupOneOff())->setEngineRuleset('diffusion-readme')->setContent($readme_content); $markup_field = 'default'; $readme_content = id(new PhabricatorMarkupEngine())->setViewer($request->getUser())->addObject($markup_object, $markup_field)->process()->getOutput($markup_object, $markup_field); $engine = $markup_object->newMarkupEngine($markup_field); $toc = PhutilRemarkupHeaderBlockRule::renderTableOfContents($engine); if ($toc) { $toc = phutil_tag_div('phabricator-remarkup-toc', array(phutil_tag_div('phabricator-remarkup-toc-header', pht('Table of Contents')), $toc)); $readme_content = array($toc, $readme_content); } $class = 'phabricator-remarkup'; break; } $readme_content = phutil_tag('div', array('class' => $class), $readme_content); return $readme_content; }
public function getBodyForFeed(PhabricatorFeedStory $story) { $text = null; switch ($this->getTransactionType()) { case PholioTransactionType::TYPE_NAME: if ($this->getOldValue() === null) { $mock = $story->getPrimaryObject(); $text = $mock->getDescription(); } break; case PholioTransactionType::TYPE_INLINE: $text = $this->getComment()->getContent(); break; } if ($text) { return phutil_escape_html_newlines(id(new PhutilUTF8StringTruncator())->setMaximumGlyphs(128)->truncateString($text)); } return parent::getBodyForFeed($story); }
public function renderPropertyViewValue(array $handles) { $diff = $this->getObject()->getActiveDiff(); $ustar = DifferentialRevisionUpdateHistoryView::renderDiffUnitStar($diff); $umsg = DifferentialRevisionUpdateHistoryView::getDiffUnitMessage($diff); $rows = array(); $rows[] = array('style' => 'star', 'name' => $ustar, 'value' => $umsg, 'show' => true); $excuse = $diff->getProperty('arc:unit-excuse'); if ($excuse) { $rows[] = array('style' => 'excuse', 'name' => 'Excuse', 'value' => phutil_escape_html_newlines($excuse), 'show' => true); } $show_limit = 10; $hidden = array(); $udata = $diff->getProperty('arc:unit'); if ($udata) { $sort_map = array(ArcanistUnitTestResult::RESULT_BROKEN => 0, ArcanistUnitTestResult::RESULT_FAIL => 1, ArcanistUnitTestResult::RESULT_UNSOUND => 2, ArcanistUnitTestResult::RESULT_SKIP => 3, ArcanistUnitTestResult::RESULT_POSTPONED => 4, ArcanistUnitTestResult::RESULT_PASS => 5); foreach ($udata as $key => $test) { $udata[$key]['sort'] = idx($sort_map, idx($test, 'result')); } $udata = isort($udata, 'sort'); $engine = new PhabricatorMarkupEngine(); $engine->setViewer($this->getViewer()); $markup_objects = array(); foreach ($udata as $key => $test) { $userdata = idx($test, 'userdata'); if ($userdata) { if ($userdata !== false) { $userdata = str_replace("", '', $userdata); } $markup_object = id(new PhabricatorMarkupOneOff())->setContent($userdata)->setPreserveLinebreaks(true); $engine->addObject($markup_object, 'default'); $markup_objects[$key] = $markup_object; } } $engine->process(); foreach ($udata as $key => $test) { $result = idx($test, 'result'); $default_hide = false; switch ($result) { case ArcanistUnitTestResult::RESULT_POSTPONED: case ArcanistUnitTestResult::RESULT_PASS: $default_hide = true; break; } if ($show_limit && !$default_hide) { --$show_limit; $show = true; } else { $show = false; if (empty($hidden[$result])) { $hidden[$result] = 0; } $hidden[$result]++; } $value = idx($test, 'name'); if (!empty($test['link'])) { $value = phutil_tag('a', array('href' => $test['link'], 'target' => '_blank'), $value); } $rows[] = array('style' => $this->getResultStyle($result), 'name' => ucwords($result), 'value' => $value, 'show' => $show); if (isset($markup_objects[$key])) { $rows[] = array('style' => 'details', 'value' => $engine->getOutput($markup_objects[$key], 'default'), 'show' => false); if (empty($hidden['details'])) { $hidden['details'] = 0; } $hidden['details']++; } } } $show_string = $this->renderShowString($hidden); $view = new DifferentialResultsTableView(); $view->setRows($rows); $view->setShowMoreString($show_string); return $view->render(); }
public function getBodyForFeed(PhabricatorFeedStory $story) { $text = null; switch ($this->getTransactionType()) { case self::TYPE_TITLE: if ($this->getOldValue() === null) { $post = $story->getPrimaryObject(); $text = $post->getBody(); } break; case self::TYPE_VISIBILITY: if ($this->getNewValue() == PhameConstants::VISIBILITY_PUBLISHED) { $post = $story->getPrimaryObject(); $text = $post->getBody(); } break; case self::TYPE_BODY: $text = $this->getNewValue(); break; } if (strlen($text)) { return phutil_escape_html_newlines(id(new PhutilUTF8StringTruncator())->setMaximumGlyphs(128)->truncateString($text)); } return parent::getBodyForFeed($story); }
public function addFragment($fragment) { $this->plaintextFragments[] = $fragment; $this->htmlFragments[] = phutil_escape_html_newlines(phutil_tag('div', array(), $fragment)); return $this; }
public function render() { $issue = $this->getIssue(); $description = array(); $description[] = phutil_tag('div', array('class' => 'setup-issue-instructions'), phutil_escape_html_newlines($issue->getMessage())); $configs = $issue->getPHPConfig(); if ($configs) { $description[] = $this->renderPHPConfig($configs, $issue); } $configs = $issue->getMySQLConfig(); if ($configs) { $description[] = $this->renderMySQLConfig($configs); } $configs = $issue->getPhabricatorConfig(); if ($configs) { $description[] = $this->renderPhabricatorConfig($configs); } $related_configs = $issue->getRelatedPhabricatorConfig(); if ($related_configs) { $description[] = $this->renderPhabricatorConfig($related_configs, $related = true); } $commands = $issue->getCommands(); if ($commands) { $run_these = pht('Run these %d command(s):', count($commands)); $description[] = phutil_tag('div', array('class' => 'setup-issue-config'), array(phutil_tag('p', array(), $run_these), phutil_tag('pre', array(), phutil_implode_html("\n", $commands)))); } $extensions = $issue->getPHPExtensions(); if ($extensions) { $install_these = pht('Install these %d PHP extension(s):', count($extensions)); $install_info = pht('You can usually install a PHP extension using %s or %s. Common ' . 'package names are %s or %s. Try commands like these:', phutil_tag('tt', array(), 'apt-get'), phutil_tag('tt', array(), 'yum'), hsprintf('<tt>php-<em>%s</em></tt>', pht('extname')), hsprintf('<tt>php5-<em>%s</em></tt>', pht('extname'))); // TODO: We should do a better job of detecting how to install extensions // on the current system. $install_commands = hsprintf("\$ sudo apt-get install php5-<em>extname</em> " . "# Debian / Ubuntu\n" . "\$ sudo yum install php-<em>extname</em> " . "# Red Hat / Derivatives"); $fallback_info = pht("If those commands don't work, try Google. The process of installing " . "PHP extensions is not specific to Phabricator, and any instructions " . "you can find for installing them on your system should work. On Mac " . "OS X, you might want to try Homebrew."); $restart_info = pht('After installing new PHP extensions, <strong>restart Phabricator ' . 'for the changes to take effect</strong>. For help with restarting ' . 'Phabricator, see %s in the documentation.', $this->renderRestartLink()); $description[] = phutil_tag('div', array('class' => 'setup-issue-config'), array(phutil_tag('p', array(), $install_these), phutil_tag('pre', array(), implode("\n", $extensions)), phutil_tag('p', array(), $install_info), phutil_tag('pre', array(), $install_commands), phutil_tag('p', array(), $fallback_info), phutil_tag('p', array(), $restart_info))); } $related_links = $issue->getLinks(); if ($related_links) { $description[] = $this->renderRelatedLinks($related_links); } $actions = array(); if (!$issue->getIsFatal()) { if ($issue->getIsIgnored()) { $actions[] = javelin_tag('a', array('href' => '/config/unignore/' . $issue->getIssueKey() . '/', 'sigil' => 'workflow', 'class' => 'button grey'), pht('Unignore Setup Issue')); } else { $actions[] = javelin_tag('a', array('href' => '/config/ignore/' . $issue->getIssueKey() . '/', 'sigil' => 'workflow', 'class' => 'button grey'), pht('Ignore Setup Issue')); } $actions[] = javelin_tag('a', array('href' => '/config/issue/' . $issue->getIssueKey() . '/', 'class' => 'button grey', 'style' => 'float: right'), pht('Reload Page')); } if ($actions) { $actions = phutil_tag('div', array('class' => 'setup-issue-actions'), $actions); } if ($issue->getIsIgnored()) { $status = phutil_tag('div', array('class' => 'setup-issue-status'), pht('This issue is currently ignored, and does not show a global ' . 'warning.')); $next = null; } else { $status = null; $next = phutil_tag('div', array('class' => 'setup-issue-next'), pht('To continue, resolve this problem and reload the page.')); } $name = phutil_tag('div', array('class' => 'setup-issue-name'), $issue->getName()); $head = phutil_tag('div', array('class' => 'setup-issue-head'), array($name, $status)); $tail = phutil_tag('div', array('class' => 'setup-issue-tail'), array($actions)); $issue = phutil_tag('div', array('class' => 'setup-issue'), array($head, $description, $tail)); $debug_info = phutil_tag('div', array('class' => 'setup-issue-debug'), pht('Host: %s', php_uname('n'))); return phutil_tag('div', array('class' => 'setup-issue-shell'), array($issue, $next, $debug_info)); }
public function getBodyForFeed(PhabricatorFeedStory $story) { $new = $this->getNewValue(); $old = $this->getOldValue(); $body = null; switch ($this->getTransactionType()) { case self::TYPE_TITLE: if ($old === null) { $question = $story->getObject($this->getObjectPHID()); return phutil_escape_html_newlines(id(new PhutilUTF8StringTruncator())->setMaximumGlyphs(128)->truncateString($question->getContent())); } break; case self::TYPE_ANSWERS: $answer = $this->getNewAnswerObject($story); if ($answer) { return phutil_escape_html_newlines(id(new PhutilUTF8StringTruncator())->setMaximumGlyphs(128)->truncateString($answer->getContent())); } break; } return parent::getBodyForFeed($story); }
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 buildRepositoryStatus(PhabricatorRepository $repository) { $viewer = $this->getRequest()->getUser(); $is_cluster = $repository->getAlmanacServicePHID(); $view = new PHUIStatusListView(); $messages = id(new PhabricatorRepositoryStatusMessage())->loadAllWhere('repositoryID = %d', $repository->getID()); $messages = mpull($messages, null, 'getStatusType'); 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()) { if ($repository->getServeOverHTTP() != PhabricatorRepository::SERVE_OFF) { 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; } } if ($repository->getServeOverSSH() != PhabricatorRepository::SERVE_OFF) { 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; case PhabricatorRepositoryStatusMessage::CODE_WORKING: $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; default: $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')->setTarget(pht('Unknown Init Status'))->setNote($message->getStatusCode())); 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.'); } $message = phutil_escape_html_newlines($message); if ($suggestion !== null) { $message = array(phutil_tag('strong', array(), $suggestion), phutil_tag('br'), phutil_tag('br'), phutil_tag('em', array(), pht('Raw Error')), phutil_tag('br'), $message); } $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')->setTarget(pht('Update Error'))->setNote($message)); 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()) { $progress = queryfx_all($repository->establishConnection('r'), 'SELECT importStatus, count(*) N FROM %T WHERE repositoryID = %d GROUP BY importStatus', id(new PhabricatorRepositoryCommit())->getTableName(), $repository->getID()); $done = 0; $total = 0; foreach ($progress as $row) { $total += $row['N'] * 4; $status = $row['importStatus']; if ($status & PhabricatorRepositoryCommit::IMPORTED_MESSAGE) { $done += $row['N']; } if ($status & PhabricatorRepositoryCommit::IMPORTED_CHANGE) { $done += $row['N']; } if ($status & PhabricatorRepositoryCommit::IMPORTED_OWNERS) { $done += $row['N']; } if ($status & PhabricatorRepositoryCommit::IMPORTED_HERALD) { $done += $row['N']; } } if ($total) { $percentage = 100 * ($done / $total); } else { $percentage = 0; } // Cap this at "99.99%", because it's confusing to users when the actual // fraction is "99.996%" and it rounds up to "100.00%". if ($percentage > 99.98999999999999) { $percentage = 99.98999999999999; } $percentage = sprintf('%.2f%%', $percentage); $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 renderRuleTypeControl(array $rule_type_map, $e_rule) { $request = $this->getRequest(); // Reorder array to put less powerful rules first. $rule_type_map = array_select_keys($rule_type_map, array(HeraldRuleTypeConfig::RULE_TYPE_PERSONAL, HeraldRuleTypeConfig::RULE_TYPE_OBJECT, HeraldRuleTypeConfig::RULE_TYPE_GLOBAL)) + $rule_type_map; list($can_global, $global_link) = $this->explainApplicationCapability(HeraldManageGlobalRulesCapability::CAPABILITY, pht('You have permission to create and manage global rules.'), pht('You do not have permission to create or manage global rules.')); $captions = array(HeraldRuleTypeConfig::RULE_TYPE_PERSONAL => pht('Personal rules notify you about events. You own them, but they can ' . 'only affect you. Personal rules only trigger for objects you have ' . 'permission to see.'), HeraldRuleTypeConfig::RULE_TYPE_OBJECT => pht('Object rules notify anyone about events. They are bound to an ' . 'object (like a repository) and can only act on that object. You ' . 'must be able to edit an object to create object rules for it. ' . 'Other users who can edit the object can edit its rules.'), HeraldRuleTypeConfig::RULE_TYPE_GLOBAL => array(pht('Global rules notify anyone about events. Global rules can ' . 'bypass access control policies and act on any object.'), $global_link)); $radio = id(new AphrontFormRadioButtonControl())->setLabel(pht('Rule Type'))->setName('rule_type')->setValue($request->getStr('rule_type'))->setError($e_rule); $adapter = HeraldAdapter::getAdapterForContentType($request->getStr('content_type')); foreach ($rule_type_map as $value => $name) { $caption = idx($captions, $value); $disabled = $value == HeraldRuleTypeConfig::RULE_TYPE_GLOBAL && !$can_global; if (!$adapter->supportsRuleType($value)) { $disabled = true; $caption = array($caption, "\n\n", phutil_tag('em', array(), pht('This rule type is not supported by the selected content type.'))); } $radio->addButton($value, $name, phutil_escape_html_newlines($caption), $disabled ? 'disabled' : null, $disabled); } return $radio; }
protected function renderPropertyChangeHeader() { $changeset = $this->getChangeset(); list($old, $new) = $this->getChangesetProperties($changeset); // If we don't have any property changes, don't render this table. if ($old === $new) { return null; } $keys = array_keys($old + $new); sort($keys); $key_map = array('unix:filemode' => pht('File Mode'), 'file:dimensions' => pht('Image Dimensions'), 'file:mimetype' => pht('MIME Type'), 'file:size' => pht('File Size')); $rows = array(); foreach ($keys as $key) { $oval = idx($old, $key); $nval = idx($new, $key); if ($oval !== $nval) { if ($oval === null) { $oval = phutil_tag('em', array(), 'null'); } else { $oval = phutil_escape_html_newlines($oval); } if ($nval === null) { $nval = phutil_tag('em', array(), 'null'); } else { $nval = phutil_escape_html_newlines($nval); } $readable_key = idx($key_map, $key, $key); $row = array($readable_key, $oval, $nval); $rows[] = $row; } } $classes = array('', 'oval', 'nval'); $headers = array(pht('Property'), pht('Old Value'), pht('New Value')); $table = id(new AphrontTableView($rows))->setHeaders($headers)->setColumnClasses($classes); return phutil_tag('div', array('class' => 'differential-property-table'), $table); }
public final function renderSummary($text, $len = 128) { if ($len) { $text = id(new PhutilUTF8StringTruncator())->setMaximumGlyphs($len)->truncateString($text); } switch ($this->getRenderingTarget()) { case PhabricatorApplicationTransaction::TARGET_HTML: $text = phutil_escape_html_newlines($text); break; } return $text; }
protected function renderHarbormasterStatus(DifferentialDiff $diff, array $messages) { $colors = array(DifferentialUnitStatus::UNIT_NONE => 'grey', DifferentialUnitStatus::UNIT_OKAY => 'green', DifferentialUnitStatus::UNIT_WARN => 'yellow', DifferentialUnitStatus::UNIT_FAIL => 'red', DifferentialUnitStatus::UNIT_SKIP => 'blue', DifferentialUnitStatus::UNIT_AUTO_SKIP => 'blue', DifferentialUnitStatus::UNIT_POSTPONED => 'blue'); $icon_color = idx($colors, $diff->getUnitStatus(), 'grey'); $message = DifferentialRevisionUpdateHistoryView::getDiffUnitMessage($diff); $note = array(); $groups = mgroup($messages, 'getResult'); $groups = array_select_keys($groups, array(ArcanistUnitTestResult::RESULT_FAIL, ArcanistUnitTestResult::RESULT_BROKEN, ArcanistUnitTestResult::RESULT_UNSOUND, ArcanistUnitTestResult::RESULT_SKIP, ArcanistUnitTestResult::RESULT_PASS)) + $groups; foreach ($groups as $result => $group) { $count = new PhutilNumber(count($group)); switch ($result) { case ArcanistUnitTestResult::RESULT_PASS: $note[] = pht('%s Passed Test(s)', $count); break; case ArcanistUnitTestResult::RESULT_FAIL: $note[] = pht('%s Failed Test(s)', $count); break; case ArcanistUnitTestResult::RESULT_SKIP: $note[] = pht('%s Skipped Test(s)', $count); break; case ArcanistUnitTestResult::RESULT_BROKEN: $note[] = pht('%s Broken Test(s)', $count); break; case ArcanistUnitTestResult::RESULT_UNSOUND: $note[] = pht('%s Unsound Test(s)', $count); break; default: $note[] = pht('%s Other Test(s)', $count); break; } } $buildable = $diff->getBuildable(); if ($buildable) { $full_results = '/harbormaster/unit/' . $buildable->getID() . '/'; $note[] = phutil_tag('a', array('href' => $full_results), pht('View Full Results')); } $excuse = $diff->getProperty('arc:unit-excuse'); if (strlen($excuse)) { $excuse = array(phutil_tag('strong', array(), pht('Excuse:')), ' ', phutil_escape_html_newlines($excuse)); $note[] = $excuse; } $note = phutil_implode_html(" · ", $note); $status = id(new PHUIStatusListView())->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_STAR, $icon_color)->setTarget($message)->setNote($note)); return $status; }
public function extendEditForm(AphrontRequest $request, AphrontFormView $form, array $values, array $issues) { if (!function_exists('openssl_pkey_new')) { // TODO: This could be a bit prettier. throw new Exception(pht("The PHP 'openssl' extension is not installed. You must install " . "this extension in order to add a JIRA authentication provider, " . "because JIRA OAuth requests use the RSA-SHA1 signing algorithm. " . "Install the 'openssl' extension, restart your webserver, and try " . "again.")); } $form->appendRemarkupInstructions(pht('NOTE: This provider **only supports JIRA 6**. It will not work with ' . 'JIRA 5 or earlier.')); $is_setup = $this->isSetup(); $viewer = $request->getViewer(); $e_required = $request->isFormPost() ? null : true; $v_name = $values[self::PROPERTY_JIRA_NAME]; if ($is_setup) { $e_name = idx($issues, self::PROPERTY_JIRA_NAME, $e_required); } else { $e_name = null; } $v_uri = $values[self::PROPERTY_JIRA_URI]; $e_uri = idx($issues, self::PROPERTY_JIRA_URI, $e_required); if ($is_setup) { $form->appendRemarkupInstructions(pht("**JIRA Instance Name**\n\n" . "Choose a permanent name for this instance of JIRA. Phabricator " . "uses this name internally to keep track of this instance of " . "JIRA, in case the URL changes later.\n\n" . "Use lowercase letters, digits, and period. For example, " . "`jira`, `jira.mycompany` or `jira.engineering` are reasonable " . "names."))->appendChild(id(new AphrontFormTextControl())->setLabel(pht('JIRA Instance Name'))->setValue($v_name)->setName(self::PROPERTY_JIRA_NAME)->setError($e_name)); } else { $form->appendChild(id(new AphrontFormStaticControl())->setLabel(pht('JIRA Instance Name'))->setValue($v_name)); } $form->appendChild(id(new AphrontFormTextControl())->setLabel(pht('JIRA Base URI'))->setValue($v_uri)->setName(self::PROPERTY_JIRA_URI)->setCaption(pht('The URI where JIRA is installed. For example: %s', phutil_tag('tt', array(), 'https://jira.mycompany.com/')))->setError($e_uri)); if (!$is_setup) { $config = $this->getProviderConfig(); $ckey = $config->getProperty(self::PROPERTY_CONSUMER_KEY); $ckey = phutil_tag('tt', array(), $ckey); $pkey = $config->getProperty(self::PROPERTY_PUBLIC_KEY); $pkey = phutil_escape_html_newlines($pkey); $pkey = phutil_tag('tt', array(), $pkey); $form->appendRemarkupInstructions(pht('NOTE: **To complete setup**, copy and paste these keys into JIRA ' . 'according to the instructions below.'))->appendChild(id(new AphrontFormStaticControl())->setLabel(pht('Consumer Key'))->setValue($ckey))->appendChild(id(new AphrontFormStaticControl())->setLabel(pht('Public Key'))->setValue($pkey)); $form->appendRemarkupInstructions(pht('= Integration Options = ' . "\n" . 'Configure how to record Revisions on JIRA tasks.' . "\n\n" . 'Note you\'ll have to restart the daemons for this to take ' . 'effect.'))->appendChild(id(new AphrontFormCheckboxControl())->addCheckbox(self::PROPERTY_REPORT_LINK, 1, new PHUIRemarkupView($viewer, pht('Create **Issue Link** to the Revision, as an "implemented ' . 'in" relationship.')), $this->shouldCreateJIRALink()))->appendChild(id(new AphrontFormCheckboxControl())->addCheckbox(self::PROPERTY_REPORT_COMMENT, 1, new PHUIRemarkupView($viewer, pht('**Post a comment** in the JIRA task, similar to the ' . 'emails Phabricator sends.')), $this->shouldCreateJIRAComment())); } }
public function renderPropertyViewValue(array $handles) { $diff = $this->getObject()->getActiveDiff(); $path_changesets = mpull($diff->loadChangesets(), 'getID', 'getFilename'); $lstar = DifferentialRevisionUpdateHistoryView::renderDiffLintStar($diff); $lmsg = DifferentialRevisionUpdateHistoryView::getDiffLintMessage($diff); $ldata = $diff->getProperty('arc:lint'); $ltail = null; $rows = array(); $rows[] = array('style' => 'star', 'name' => $lstar, 'value' => $lmsg, 'show' => true); $excuse = $diff->getProperty('arc:lint-excuse'); if ($excuse) { $rows[] = array('style' => 'excuse', 'name' => 'Excuse', 'value' => phutil_escape_html_newlines($excuse), 'show' => true); } $show_limit = 10; $hidden = array(); if ($ldata) { $ldata = igroup($ldata, 'path'); foreach ($ldata as $path => $messages) { $rows[] = array('style' => 'section', 'name' => $path, 'show' => $show_limit); foreach ($messages as $message) { $path = idx($message, 'path'); $line = idx($message, 'line'); $code = idx($message, 'code'); $severity = idx($message, 'severity'); $name = idx($message, 'name'); $description = idx($message, 'description'); $line_link = 'line ' . intval($line); if (isset($path_changesets[$path])) { $href = '#C' . $path_changesets[$path] . 'NL' . max(1, $line); // TODO: We are always showing the active diff // if ($diff->getID() != $this->getDiff()->getID()) { // $href = '/D'.$diff->getRevisionID().'?id='.$diff->getID().$href; // } $line_link = phutil_tag('a', array('href' => $href), $line_link); } if ($show_limit) { --$show_limit; $show = true; } else { $show = false; if (empty($hidden[$severity])) { $hidden[$severity] = 0; } $hidden[$severity]++; } $rows[] = array('style' => $this->getSeverityStyle($severity), 'name' => ucwords($severity), 'value' => hsprintf('(%s) %s at %s', $code, $name, $line_link), 'show' => $show); if (!empty($message['locations'])) { $locations = array(); foreach ($message['locations'] as $location) { $other_line = idx($location, 'line'); $locations[] = idx($location, 'path', $path) . ($other_line ? ":{$other_line}" : ''); } $description .= "\nOther locations: " . implode(', ', $locations); } if (strlen($description)) { $rows[] = array('style' => 'details', 'value' => phutil_escape_html_newlines($description), 'show' => false); if (empty($hidden['details'])) { $hidden['details'] = 0; } $hidden['details']++; } } } } $postponed = $diff->getProperty('arc:lint-postponed'); if ($postponed) { foreach ($postponed as $linter) { $rows[] = array('style' => $this->getPostponedStyle(), 'name' => 'Postponed', 'value' => $linter, 'show' => false); if (empty($hidden['postponed'])) { $hidden['postponed'] = 0; } $hidden['postponed']++; } } $show_string = $this->renderShowString($hidden); $view = new DifferentialResultsTableView(); $view->setRows($rows); $view->setShowMoreString($show_string); return $view->render(); }
public function render() { $user = $this->user; if (!$user) { throw new PhutilInvalidStateException('setUser'); } $local = $this->localCommits; if (!$local) { return null; } $has_tree = false; $has_local = false; foreach ($local as $commit) { if (idx($commit, 'tree')) { $has_tree = true; } if (idx($commit, 'local')) { $has_local = true; } } $rows = array(); foreach ($local as $commit) { $row = array(); if (idx($commit, 'commit')) { $commit_link = $this->buildCommitLink($commit['commit']); } else { if (isset($commit['rev'])) { $commit_link = $this->buildCommitLink($commit['rev']); } else { $commit_link = null; } } $row[] = $commit_link; if ($has_tree) { $row[] = $this->buildCommitLink($commit['tree']); } if ($has_local) { $row[] = $this->buildCommitLink($commit['local']); } $parents = idx($commit, 'parents', array()); foreach ($parents as $k => $parent) { if (is_array($parent)) { $parent = idx($parent, 'rev'); } $parents[$k] = $this->buildCommitLink($parent); } $parents = phutil_implode_html(phutil_tag('br'), $parents); $row[] = $parents; $author = nonempty(idx($commit, 'user'), idx($commit, 'author')); $row[] = $author; $message = idx($commit, 'message'); $summary = idx($commit, 'summary'); $summary = id(new PhutilUTF8StringTruncator())->setMaximumGlyphs(80)->truncateString($summary); $view = new AphrontMoreView(); $view->setSome($summary); if ($message && trim($summary) != trim($message)) { $view->setMore(phutil_escape_html_newlines($message)); } $row[] = $view->render(); $date = nonempty(idx($commit, 'date'), idx($commit, 'time')); if ($date) { $date = phabricator_datetime($date, $user); } $row[] = $date; $rows[] = $row; } $column_classes = array(''); if ($has_tree) { $column_classes[] = ''; } if ($has_local) { $column_classes[] = ''; } $column_classes[] = ''; $column_classes[] = ''; $column_classes[] = 'wide'; $column_classes[] = 'date'; $table = id(new AphrontTableView($rows))->setColumnClasses($column_classes); $headers = array(); $headers[] = pht('Commit'); if ($has_tree) { $headers[] = pht('Tree'); } if ($has_local) { $headers[] = pht('Local'); } $headers[] = pht('Parents'); $headers[] = pht('Author'); $headers[] = pht('Summary'); $headers[] = pht('Date'); $table->setHeaders($headers); return id(new PHUIObjectBoxView())->setHeaderText(pht('Local Commits'))->setTable($table); }