public function render()
 {
     $data = $this->getData();
     $lib_data = $data['libraries'];
     $lib_rows = array();
     foreach ($lib_data as $key => $value) {
         $lib_rows[] = array(phutil_escape_html($key), phutil_escape_html($value));
     }
     $lib_table = new AphrontTableView($lib_rows);
     $lib_table->setHeaders(array('Library', 'Loaded From'));
     $lib_table->setColumnClasses(array('header', 'wide wrap'));
     $config_data = $data['config'];
     ksort($config_data);
     $mask = PhabricatorEnv::getEnvConfig('darkconsole.config-mask');
     $mask = array_fill_keys($mask, true);
     foreach ($mask as $masked_key => $ignored) {
         if (!PhabricatorEnv::envConfigExists($masked_key)) {
             throw new Exception("Configuration 'darkconsole.config-mask' masks unknown " . "configuration key '" . $masked_key . "'. If this key has been " . "renamed, you might be accidentally exposing information which you " . "don't intend to.");
         }
     }
     $rows = array();
     foreach ($config_data as $key => $value) {
         if (empty($mask[$key])) {
             $display_value = is_array($value) ? json_encode($value) : $value;
             $display_value = phutil_escape_html($display_value);
         } else {
             $display_value = phutil_escape_html('<Masked>');
         }
         $rows[] = array(phutil_escape_html($key), $display_value);
     }
     $table = new AphrontTableView($rows);
     $table->setHeaders(array('Key', 'Value'));
     $table->setColumnClasses(array('header', 'wide wrap'));
     return $lib_table->render() . $table->render();
 }
 public function renderPanel()
 {
     $data = $this->getData();
     $sections = array('Basics' => array('Machine' => php_uname('n')));
     // NOTE: This may not be present for some SAPIs, like php-fpm.
     if (!empty($data['Server']['SERVER_ADDR'])) {
         $addr = $data['Server']['SERVER_ADDR'];
         $sections['Basics']['Host'] = $addr;
         $sections['Basics']['Hostname'] = @gethostbyaddr($addr);
     }
     $sections = array_merge($sections, $data);
     $mask = array('HTTP_COOKIE' => true, 'HTTP_X_PHABRICATOR_CSRF' => true);
     $out = array();
     foreach ($sections as $header => $map) {
         $rows = array();
         foreach ($map as $key => $value) {
             if (isset($mask[$key])) {
                 $rows[] = array($key, phutil_tag('em', array(), '(Masked)'));
             } else {
                 $rows[] = array($key, is_array($value) ? json_encode($value) : $value);
             }
         }
         $table = new AphrontTableView($rows);
         $table->setHeaders(array($header, null));
         $table->setColumnClasses(array('header', 'wide wrap'));
         $out[] = $table->render();
     }
     return phutil_implode_html("\n", $out);
 }
 public function render()
 {
     $drequest = $this->getDiffusionRequest();
     $handles = $this->handles;
     $rows = array();
     foreach ($this->history as $history) {
         $epoch = $history->getEpoch();
         if ($epoch) {
             $date = date('M j, Y', $epoch);
             $time = date('g:i A', $epoch);
         } else {
             $date = null;
             $time = null;
         }
         $data = $history->getCommitData();
         $author_phid = null;
         if ($data) {
             $author_phid = $data->getCommitDetail('authorPHID');
         }
         if ($author_phid && isset($handles[$author_phid])) {
             $author = $handles[$author_phid]->renderLink();
         } else {
             $author = phutil_escape_html($history->getAuthorName());
         }
         $rows[] = array($this->linkBrowse($drequest->getPath(), array('commit' => $history->getCommitIdentifier())), self::linkCommit($drequest->getRepository(), $history->getCommitIdentifier()), $this->linkChange($history->getChangeType(), $history->getFileType(), null, $history->getCommitIdentifier()), $date, $time, $author, phutil_escape_html($history->getSummary()));
     }
     $view = new AphrontTableView($rows);
     $view->setHeaders(array('Browse', 'Commit', 'Change', 'Date', 'Time', 'Author', 'Details'));
     $view->setColumnClasses(array('', 'n', '', '', 'right', '', 'wide wrap'));
     return $view->render();
 }
 public function render()
 {
     $drequest = $this->getDiffusionRequest();
     $current_branch = $drequest->getBranch();
     $rows = array();
     $rowc = array();
     foreach ($this->branches as $branch) {
         $commit = idx($this->commits, $branch->getHeadCommitIdentifier());
         if ($commit) {
             $details = $commit->getCommitData()->getCommitMessage();
             $details = idx(explode("\n", $details), 0);
             $details = substr($details, 0, 80);
             $datetime = phabricator_datetime($commit->getEpoch(), $this->user);
         } else {
             $datetime = null;
             $details = null;
         }
         $rows[] = array(phutil_render_tag('a', array('href' => $drequest->generateURI(array('action' => 'history', 'branch' => $branch->getName()))), 'History'), phutil_render_tag('a', array('href' => $drequest->generateURI(array('action' => 'browse', 'branch' => $branch->getName()))), phutil_escape_html($branch->getName())), self::linkCommit($drequest->getRepository(), $branch->getHeadCommitIdentifier()), $datetime, AphrontTableView::renderSingleDisplayLine(phutil_escape_html($details)));
         if ($branch->getName() == $current_branch) {
             $rowc[] = 'highlighted';
         } else {
             $rowc[] = null;
         }
     }
     $view = new AphrontTableView($rows);
     $view->setHeaders(array('History', 'Branch', 'Head', 'Modified', 'Details'));
     $view->setColumnClasses(array('', 'pri', '', '', 'wide'));
     $view->setRowClasses($rowc);
     return $view->render();
 }
 public function render()
 {
     $rows = array();
     if (!$this->user) {
         throw new Exception("Call setUser() before rendering!");
     }
     foreach ($this->daemonLogs as $log) {
         $epoch = $log->getDateCreated();
         if ($log->getHost() == php_uname('n')) {
             $pid = $log->getPID();
             $is_running = PhabricatorDaemonReference::isProcessRunning($pid);
             if ($is_running) {
                 $running = phutil_render_tag('span', array('style' => 'color: #00cc00', 'title' => 'Running'), '&bull;');
             } else {
                 $running = phutil_render_tag('span', array('style' => 'color: #cc0000', 'title' => 'Not running'), '&bull;');
             }
         } else {
             $running = phutil_render_tag('span', array('style' => 'color: #888888', 'title' => 'Not on this host'), '?');
         }
         $rows[] = array($running, phutil_escape_html($log->getDaemon()), phutil_escape_html($log->getHost()), $log->getPID(), phabricator_date($epoch, $this->user), phabricator_time($epoch, $this->user), phutil_render_tag('a', array('href' => '/daemon/log/' . $log->getID() . '/', 'class' => 'button small grey'), 'View Log'));
     }
     $daemon_table = new AphrontTableView($rows);
     $daemon_table->setHeaders(array('', 'Daemon', 'Host', 'PID', 'Date', 'Time', 'View'));
     $daemon_table->setColumnClasses(array('', 'wide wrap', '', '', '', 'right', 'action'));
     return $daemon_table->render();
 }
 public function render()
 {
     $data = $this->getData();
     $rows = array();
     $details = '';
     foreach ($data as $index => $row) {
         $file = $row['file'];
         $line = $row['line'];
         $tag = phutil_render_tag('a', array('onclick' => jsprintf('show_details(%d)', $index)), phutil_escape_html($row['str'] . ' at [' . basename($file) . ':' . $line . ']'));
         $rows[] = array($tag);
         $details .= '<div class="dark-console-panel-error-details" id="row-details-' . $index . '">' . phutil_escape_html($row['details']) . "\n" . 'Stack trace:' . "\n";
         foreach ($row['trace'] as $key => $entry) {
             $line = '';
             if (isset($entry['class'])) {
                 $line .= $entry['class'] . '::';
             }
             $line .= idx($entry, 'function', '');
             $onclick = '';
             if (isset($entry['file'])) {
                 $line .= ' called at [' . $entry['file'] . ':' . $entry['line'] . ']';
                 $onclick = jsprintf('open_file(%s, %d)', $entry['file'], $entry['line']);
             }
             $details .= phutil_render_tag('a', array('onclick' => $onclick), phutil_escape_html($line));
             $details .= "\n";
         }
         $details .= '</div>';
     }
     $table = new AphrontTableView($rows);
     $table->setClassName('error-log');
     $table->setHeaders(array('Error'));
     $table->setNoDataString('No errors.');
     return '<div>' . '<div>' . $table->render() . '</div>' . '<div class="dark-console-panel-error-separator"></div>' . '<pre class="PhabricatorMonospaced">' . $details . '</pre>' . '</div>';
 }
 public function render()
 {
     $rows = array();
     foreach ($this->edits as $edit) {
         $name = nonempty($edit->getRuleName(), 'Unknown Rule');
         $rule_name = phutil_render_tag('strong', array(), phutil_escape_html($name));
         switch ($edit->getAction()) {
             case 'create':
                 $details = "Created rule '{$rule_name}'.";
                 break;
             case 'delete':
                 $details = "Deleted rule '{$rule_name}'.";
                 break;
             case 'edit':
             default:
                 $details = "Edited rule '{$rule_name}'.";
                 break;
         }
         $rows[] = array($edit->getRuleID(), $this->handles[$edit->getEditorPHID()]->renderLink(), $details, phabricator_datetime($edit->getDateCreated(), $this->user));
     }
     $table = new AphrontTableView($rows);
     $table->setNoDataString("No edits for rule.");
     $table->setHeaders(array('Rule ID', 'Editor', 'Details', 'Edit Date'));
     $table->setColumnClasses(array('', '', 'wide', ''));
     return $table->render();
 }
 public function render()
 {
     $rows = array();
     $rowc = array();
     // TODO: Experiment with path stack rendering.
     // TODO: Copy Away and Move Away are rendered junkily still.
     foreach ($this->pathChanges as $id => $change) {
         $path = $change->getPath();
         $hash = substr(md5($path), 0, 8);
         if ($change->getFileType() == DifferentialChangeType::FILE_DIRECTORY) {
             $path .= '/';
         }
         if (isset($this->renderingReferences[$id])) {
             $path_column = javelin_render_tag('a', array('href' => '#' . $hash, 'meta' => array('id' => 'diff-' . $hash, 'ref' => $this->renderingReferences[$id]), 'sigil' => 'differential-load'), phutil_escape_html($path));
         } else {
             $path_column = phutil_escape_html($path);
         }
         $rows[] = array($this->linkHistory($change->getPath()), $this->linkBrowse($change->getPath()), $this->linkChange($change->getChangeType(), $change->getFileType(), $change->getPath()), $path_column);
         $row_class = null;
         foreach ($this->ownersPaths as $owners_path) {
             $owners_path = $owners_path->getPath();
             if (strncmp('/' . $path, $owners_path, strlen($owners_path)) == 0) {
                 $row_class = 'highlighted';
                 break;
             }
         }
         $rowc[] = $row_class;
     }
     $view = new AphrontTableView($rows);
     $view->setHeaders(array('History', 'Browse', 'Change', 'Path'));
     $view->setColumnClasses(array('', '', '', 'wide'));
     $view->setRowClasses($rowc);
     $view->setNoDataString('This change has not been fully parsed yet.');
     return $view->render();
 }
 public function render()
 {
     $viewer = $this->getViewer();
     $rows = array();
     foreach ($this->events as $event) {
         // Limit display log size. If a daemon gets stuck in an output loop this
         // page can be like >100MB if we don't truncate stuff. Try to do cheap
         // line-based truncation first, and fall back to expensive UTF-8 character
         // truncation if that doesn't get things short enough.
         $message = $event->getMessage();
         $more = null;
         if (!$this->showFullMessage) {
             $more_lines = null;
             $more_chars = null;
             $line_limit = 12;
             if (substr_count($message, "\n") > $line_limit) {
                 $message = explode("\n", $message);
                 $more_lines = count($message) - $line_limit;
                 $message = array_slice($message, 0, $line_limit);
                 $message = implode("\n", $message);
             }
             $char_limit = 8192;
             if (strlen($message) > $char_limit) {
                 $message = phutil_utf8v($message);
                 $more_chars = count($message) - $char_limit;
                 $message = array_slice($message, 0, $char_limit);
                 $message = implode('', $message);
             }
             if ($more_chars) {
                 $more = new PhutilNumber($more_chars);
                 $more = pht('Show %d more character(s)...', $more);
             } else {
                 if ($more_lines) {
                     $more = new PhutilNumber($more_lines);
                     $more = pht('Show %d more line(s)...', $more);
                 }
             }
             if ($more) {
                 $id = $event->getID();
                 $more = array("\n...\n", phutil_tag('a', array('href' => "/daemon/event/{$id}/"), $more));
             }
         }
         $row = array($event->getLogType(), phabricator_date($event->getEpoch(), $viewer), phabricator_time($event->getEpoch(), $viewer), array($message, $more));
         if ($this->combinedLog) {
             array_unshift($row, phutil_tag('a', array('href' => '/daemon/log/' . $event->getLogID() . '/'), pht('Daemon %s', $event->getLogID())));
         }
         $rows[] = $row;
     }
     $classes = array('', '', 'right', 'wide prewrap');
     $headers = array('Type', 'Date', 'Time', 'Message');
     if ($this->combinedLog) {
         array_unshift($classes, 'pri');
         array_unshift($headers, 'Daemon');
     }
     $log_table = new AphrontTableView($rows);
     $log_table->setHeaders($headers);
     $log_table->setColumnClasses($classes);
     return $log_table->render();
 }
 public function render()
 {
     $drequest = $this->getDiffusionRequest();
     $current_branch = $drequest->getBranch();
     $repository = $drequest->getRepository();
     Javelin::initBehavior('phabricator-tooltips');
     $doc_href = PhabricatorEnv::getDoclink('Diffusion User Guide: Autoclose');
     $rows = array();
     $rowc = array();
     foreach ($this->branches as $branch) {
         $commit = idx($this->commits, $branch->getCommitIdentifier());
         if ($commit) {
             $details = $commit->getSummary();
             $datetime = phabricator_datetime($commit->getEpoch(), $this->user);
         } else {
             $datetime = null;
             $details = null;
         }
         switch ($repository->shouldSkipAutocloseBranch($branch->getShortName())) {
             case PhabricatorRepository::BECAUSE_REPOSITORY_IMPORTING:
                 $icon = 'fa-times bluegrey';
                 $tip = pht('Repository Importing');
                 break;
             case PhabricatorRepository::BECAUSE_AUTOCLOSE_DISABLED:
                 $icon = 'fa-times bluegrey';
                 $tip = pht('Repository Autoclose Disabled');
                 break;
             case PhabricatorRepository::BECAUSE_BRANCH_UNTRACKED:
                 $icon = 'fa-times bluegrey';
                 $tip = pht('Branch Untracked');
                 break;
             case PhabricatorRepository::BECAUSE_BRANCH_NOT_AUTOCLOSE:
                 $icon = 'fa-times bluegrey';
                 $tip = pht('Branch Autoclose Disabled');
                 break;
             case null:
                 $icon = 'fa-check bluegrey';
                 $tip = pht('Autoclose Enabled');
                 break;
             default:
                 $icon = 'fa-question';
                 $tip = pht('Status Unknown');
                 break;
         }
         $status_icon = id(new PHUIIconView())->setIconFont($icon)->addSigil('has-tooltip')->setHref($doc_href)->setMetadata(array('tip' => $tip, 'size' => 200));
         $rows[] = array(phutil_tag('a', array('href' => $drequest->generateURI(array('action' => 'history', 'branch' => $branch->getShortName()))), pht('History')), phutil_tag('a', array('href' => $drequest->generateURI(array('action' => 'browse', 'branch' => $branch->getShortName()))), $branch->getShortName()), self::linkCommit($drequest->getRepository(), $branch->getCommitIdentifier()), $status_icon, $datetime, AphrontTableView::renderSingleDisplayLine($details));
         if ($branch->getShortName() == $current_branch) {
             $rowc[] = 'highlighted';
         } else {
             $rowc[] = null;
         }
     }
     $view = new AphrontTableView($rows);
     $view->setHeaders(array(pht('History'), pht('Branch'), pht('Head'), pht(''), pht('Modified'), pht('Details')));
     $view->setColumnClasses(array('', 'pri', '', '', '', 'wide'));
     $view->setRowClasses($rowc);
     return $view->render();
 }
 public function render()
 {
     $user = $this->getUser();
     $trace = $this->trace;
     $libraries = PhutilBootloader::getInstance()->getAllLibraries();
     // TODO: Make this configurable?
     $path = 'https://secure.phabricator.com/diffusion/%s/browse/master/src/';
     $callsigns = array('arcanist' => 'ARC', 'phutil' => 'PHU', 'phabricator' => 'P');
     $rows = array();
     $depth = count($trace);
     foreach ($trace as $part) {
         $lib = null;
         $file = idx($part, 'file');
         $relative = $file;
         foreach ($libraries as $library) {
             $root = phutil_get_library_root($library);
             if (Filesystem::isDescendant($file, $root)) {
                 $lib = $library;
                 $relative = Filesystem::readablePath($file, $root);
                 break;
             }
         }
         $where = '';
         if (isset($part['class'])) {
             $where .= $part['class'] . '::';
         }
         if (isset($part['function'])) {
             $where .= $part['function'] . '()';
         }
         if ($file) {
             if (isset($callsigns[$lib])) {
                 $attrs = array('title' => $file);
                 try {
                     $attrs['href'] = $user->loadEditorLink('/src/' . $relative, $part['line'], $callsigns[$lib]);
                 } catch (Exception $ex) {
                     // The database can be inaccessible.
                 }
                 if (empty($attrs['href'])) {
                     $attrs['href'] = sprintf($path, $callsigns[$lib]) . str_replace(DIRECTORY_SEPARATOR, '/', $relative) . '$' . $part['line'];
                     $attrs['target'] = '_blank';
                 }
                 $file_name = phutil_tag('a', $attrs, $relative);
             } else {
                 $file_name = phutil_tag('span', array('title' => $file), $relative);
             }
             $file_name = hsprintf('%s : %d', $file_name, $part['line']);
         } else {
             $file_name = phutil_tag('em', array(), '(Internal)');
         }
         $rows[] = array($depth--, $lib, $file_name, $where);
     }
     $table = new AphrontTableView($rows);
     $table->setHeaders(array(pht('Depth'), pht('Library'), pht('File'), pht('Where')));
     $table->setColumnClasses(array('n', '', '', 'wide'));
     return phutil_tag('div', array('class' => 'exception-trace'), $table->render());
 }
 public function render()
 {
     $rows = array();
     if (!$this->user) {
         throw new Exception("Call setUser() before rendering!");
     }
     foreach ($this->daemonLogs as $log) {
         $epoch = $log->getDateCreated();
         $status = $log->getStatus();
         if ($log->getHost() == php_uname('n') && $status != PhabricatorDaemonLog::STATUS_EXITED && $status != PhabricatorDaemonLog::STATUS_DEAD) {
             $pid = $log->getPID();
             $is_running = PhabricatorDaemonReference::isProcessRunning($pid);
             if (!$is_running) {
                 $guard = AphrontWriteGuard::beginScopedUnguardedWrites();
                 $log->setStatus(PhabricatorDaemonLog::STATUS_DEAD);
                 $log->save();
                 unset($guard);
                 $status = PhabricatorDaemonLog::STATUS_DEAD;
             }
         }
         $heartbeat_timeout = $log->getDateModified() + 3 * PhutilDaemonOverseer::HEARTBEAT_WAIT;
         if ($status == PhabricatorDaemonLog::STATUS_RUNNING && $heartbeat_timeout < time()) {
             $status = PhabricatorDaemonLog::STATUS_UNKNOWN;
         }
         switch ($status) {
             case PhabricatorDaemonLog::STATUS_RUNNING:
                 $style = 'color: #00cc00';
                 $title = 'Running';
                 $symbol = '&bull;';
                 break;
             case PhabricatorDaemonLog::STATUS_DEAD:
                 $style = 'color: #cc0000';
                 $title = 'Died';
                 $symbol = '&bull;';
                 break;
             case PhabricatorDaemonLog::STATUS_EXITED:
                 $style = 'color: #000000';
                 $title = 'Exited';
                 $symbol = '&bull;';
                 break;
             case PhabricatorDaemonLog::STATUS_UNKNOWN:
             default:
                 // fallthrough
                 $style = 'color: #888888';
                 $title = 'Unknown';
                 $symbol = '?';
         }
         $running = phutil_render_tag('span', array('style' => $style, 'title' => $title), $symbol);
         $rows[] = array($running, phutil_escape_html($log->getDaemon()), phutil_escape_html($log->getHost()), $log->getPID(), phabricator_date($epoch, $this->user), phabricator_time($epoch, $this->user), phutil_render_tag('a', array('href' => '/daemon/log/' . $log->getID() . '/', 'class' => 'button small grey'), 'View Log'));
     }
     $daemon_table = new AphrontTableView($rows);
     $daemon_table->setHeaders(array('', 'Daemon', 'Host', 'PID', 'Date', 'Time', 'View'));
     $daemon_table->setColumnClasses(array('', 'wide wrap', '', '', '', 'right', 'action'));
     return $daemon_table->render();
 }
 public function render()
 {
     $request = $this->getDiffusionRequest();
     $repository = $request->getRepository();
     $base_path = trim($request->getPath(), '/');
     if ($base_path) {
         $base_path = $base_path . '/';
     }
     $need_pull = array();
     $rows = array();
     $show_edit = false;
     foreach ($this->paths as $path) {
         $full_path = $base_path . $path->getPath();
         $dir_slash = null;
         $file_type = $path->getFileType();
         if ($file_type == DifferentialChangeType::FILE_DIRECTORY) {
             $browse_text = $path->getPath() . '/';
             $dir_slash = '/';
             $browse_link = phutil_tag('strong', array(), $this->linkBrowse($full_path . $dir_slash, array('type' => $file_type, 'name' => $browse_text)));
             $history_path = $full_path . '/';
         } else {
             if ($file_type == DifferentialChangeType::FILE_SUBMODULE) {
                 $browse_text = $path->getPath() . '/';
                 $browse_link = phutil_tag('strong', array(), $this->linkBrowse(null, array('type' => $file_type, 'name' => $browse_text, 'hash' => $path->getHash(), 'external' => $path->getExternalURI())));
                 $history_path = $full_path . '/';
             } else {
                 $browse_text = $path->getPath();
                 $browse_link = $this->linkBrowse($full_path, array('type' => $file_type, 'name' => $browse_text));
                 $history_path = $full_path;
             }
         }
         $history_link = $this->linkHistory($history_path);
         $dict = array('lint' => celerity_generate_unique_node_id(), 'commit' => celerity_generate_unique_node_id(), 'date' => celerity_generate_unique_node_id(), 'author' => celerity_generate_unique_node_id(), 'details' => celerity_generate_unique_node_id());
         $need_pull[$full_path . $dir_slash] = $dict;
         foreach ($dict as $k => $uniq) {
             $dict[$k] = phutil_tag('span', array('id' => $uniq), '');
         }
         $rows[] = array($history_link, $browse_link, idx($dict, 'lint'), $dict['commit'], $dict['details'], $dict['date']);
     }
     if ($need_pull) {
         Javelin::initBehavior('diffusion-pull-lastmodified', array('uri' => (string) $request->generateURI(array('action' => 'lastmodified', 'stable' => true)), 'map' => $need_pull));
     }
     $branch = $this->getDiffusionRequest()->loadBranch();
     $show_lint = $branch && $branch->getLintCommit();
     $lint = $request->getLint();
     $view = new AphrontTableView($rows);
     $view->setHeaders(array(null, pht('Path'), $lint ? $lint : pht('Lint'), pht('Modified'), pht('Details'), pht('Committed')));
     $view->setColumnClasses(array('nudgeright', '', '', '', 'wide', 'right'));
     $view->setColumnVisibility(array(true, true, $show_lint, true, true, true));
     $view->setDeviceVisibility(array(true, true, false, false, true, false));
     return $view->render();
 }
 public function render()
 {
     $user = $this->user;
     require_celerity_resource('phabricator-flag-css');
     $rows = array();
     foreach ($this->flags as $flag) {
         $class = PhabricatorFlagColor::getCSSClass($flag->getColor());
         $rows[] = array(phutil_render_tag('div', array('class' => 'phabricator-flag-icon ' . $class), ''), $flag->getHandle()->renderLink(), phutil_escape_html($flag->getNote()), phabricator_datetime($flag->getDateCreated(), $user), phabricator_render_form($user, array('method' => 'POST', 'action' => '/flag/edit/' . $flag->getObjectPHID() . '/', 'sigil' => 'workflow'), phutil_render_tag('button', array('class' => 'small grey'), 'Edit Flag')), phabricator_render_form($user, array('method' => 'POST', 'action' => '/flag/delete/' . $flag->getID() . '/', 'sigil' => 'workflow'), phutil_render_tag('button', array('class' => 'small grey'), 'Remove Flag')));
     }
     $table = new AphrontTableView($rows);
     $table->setHeaders(array('', 'Flagged Object', 'Note', 'Flagged On', '', ''));
     $table->setColumnClasses(array('', 'pri', 'wide', '', 'action', 'action'));
     $table->setNoDataString('No flags.');
     return $table->render();
 }
 public function render()
 {
     $data = $this->getData();
     $sections = array('Basics' => array('Host' => $data['Server']['SERVER_ADDR'], 'Hostname' => gethostbyaddr($data['Server']['SERVER_ADDR']), 'Machine' => php_uname('n')));
     $sections = array_merge($sections, $data);
     $out = array();
     foreach ($sections as $header => $map) {
         $rows = array();
         foreach ($map as $key => $value) {
             $rows[] = array(phutil_escape_html($key), phutil_escape_html(is_array($value) ? json_encode($value) : $value));
         }
         $table = new AphrontTableView($rows);
         $table->setHeaders(array($header, null));
         $table->setColumnClasses(array('header', 'wide wrap'));
         $out[] = $table->render();
     }
     return implode("\n", $out);
 }
 public function render()
 {
     $rows = array();
     // TODO: Experiment with path stack rendering.
     // TODO: Copy Away and Move Away are rendered junkily still.
     foreach ($this->pathChanges as $change) {
         $path = $change->getPath();
         $hash = substr(md5($path), 0, 8);
         if ($change->getFileType() == DifferentialChangeType::FILE_DIRECTORY) {
             $path .= '/';
         }
         $path_column = phutil_render_tag('a', array('href' => '#' . $hash), phutil_escape_html($path));
         $rows[] = array($this->linkHistory($change->getPath()), $this->linkBrowse($change->getPath()), $this->linkChange($change->getChangeType(), $change->getFileType(), $change->getPath()), $path_column);
     }
     $view = new AphrontTableView($rows);
     $view->setHeaders(array('History', 'Browse', 'Change', 'Path'));
     $view->setColumnClasses(array('', '', '', 'wide'));
     $view->setNoDataString('This change has not been fully parsed yet.');
     return $view->render();
 }
 public function render()
 {
     $drequest = $this->getDiffusionRequest();
     $current_branch = $drequest->getBranch();
     $rows = array();
     $rowc = array();
     foreach ($this->branches as $branch) {
         $rows[] = array(phutil_render_tag('a', array('href' => $drequest->generateURI(array('action' => 'branch', 'branch' => $branch->getName()))), phutil_escape_html($branch->getName())), self::linkCommit($drequest->getRepository(), $branch->getHeadCommitIdentifier()));
         if ($branch->getName() == $current_branch) {
             $rowc[] = 'highlighted';
         } else {
             $rowc[] = null;
         }
     }
     $view = new AphrontTableView($rows);
     $view->setHeaders(array('Branch', 'Head'));
     $view->setColumnClasses(array('wide'));
     $view->setRowClasses($rowc);
     return $view->render();
 }
 public function render()
 {
     $drequest = $this->getDiffusionRequest();
     $repository = $drequest->getRepository();
     $rows = array();
     foreach ($this->tags as $tag) {
         $commit = idx($this->commits, $tag->getCommitIdentifier());
         $tag_link = phutil_render_tag('a', array('href' => $drequest->generateURI(array('action' => 'browse', 'commit' => $tag->getName()))), phutil_escape_html($tag->getName()));
         $commit_link = phutil_render_tag('a', array('href' => $drequest->generateURI(array('action' => 'commit', 'commit' => $tag->getCommitIdentifier()))), phutil_escape_html($repository->formatCommitName($tag->getCommitIdentifier())));
         $author = null;
         if ($commit && $commit->getAuthorPHID()) {
             $author = $this->handles[$commit->getAuthorPHID()]->renderLink();
         } else {
             if ($commit && $commit->getCommitData()) {
                 $author = self::renderName($commit->getCommitData()->getAuthorName());
             } else {
                 $author = self::renderName($tag->getAuthor());
             }
         }
         $description = null;
         if ($tag->getType() == 'git/tag') {
             // In Git, a tag may be a "real" tag, or just a reference to a commit.
             // If it's a real tag, use the message on the tag, since this may be
             // unique data which isn't otherwise available.
             $description = $tag->getDescription();
         } else {
             if ($commit && $commit->getCommitData()) {
                 $description = $commit->getCommitData()->getSummary();
             } else {
                 $description = $tag->getDescription();
             }
         }
         $description = phutil_escape_html($description);
         $rows[] = array($tag_link, $commit_link, $description, $author, phabricator_datetime($tag->getEpoch(), $this->user));
     }
     $table = new AphrontTableView($rows);
     $table->setHeaders(array('Tag', 'Commit', 'Description', 'Author', 'Created'));
     $table->setColumnClasses(array('pri', '', 'wide'));
     return $table->render();
 }
 public function render()
 {
     $type_map = HeraldRuleTypeConfig::getRuleTypeMap();
     $rows = array();
     foreach ($this->rules as $rule) {
         if ($rule->getRuleType() == HeraldRuleTypeConfig::RULE_TYPE_GLOBAL) {
             $author = null;
         } else {
             $author = $this->handles[$rule->getAuthorPHID()]->renderLink();
         }
         $name = phutil_render_tag('a', array('href' => '/herald/rule/' . $rule->getID() . '/'), phutil_escape_html($rule->getName()));
         $edit_log = phutil_render_tag('a', array('href' => '/herald/history/' . $rule->getID() . '/'), 'View Edit Log');
         $delete = javelin_render_tag('a', array('href' => '/herald/delete/' . $rule->getID() . '/', 'sigil' => 'workflow', 'class' => 'button small grey'), 'Delete');
         $rows[] = array($type_map[$rule->getRuleType()], $author, $name, $edit_log, $delete);
     }
     $table = new AphrontTableView($rows);
     $table->setNoDataString("No matching rules.");
     $table->setHeaders(array('Rule Type', 'Author', 'Rule Name', 'Edit Log', ''));
     $table->setColumnClasses(array('', '', 'wide pri', '', 'action'));
     $table->setColumnVisibility(array($this->showRuleType, $this->showAuthor, true, true, true));
     return $table->render();
 }
 public function renderPanel()
 {
     $data = $this->getData();
     $rows = array();
     $details = array();
     foreach ($data as $index => $row) {
         $file = $row['file'];
         $line = $row['line'];
         $tag = phutil_tag('a', array('onclick' => jsprintf('show_details(%d)', $index)), $row['str'] . ' at [' . basename($file) . ':' . $line . ']');
         $rows[] = array($tag);
         $details[] = hsprintf('<div class="dark-console-panel-error-details" id="row-details-%s">' . "%s\nStack trace:\n", $index, $row['details']);
         foreach ($row['trace'] as $key => $entry) {
             $line = '';
             if (isset($entry['class'])) {
                 $line .= $entry['class'] . '::';
             }
             $line .= idx($entry, 'function', '');
             $href = null;
             if (isset($entry['file'])) {
                 $line .= ' called at [' . $entry['file'] . ':' . $entry['line'] . ']';
                 try {
                     $user = $this->getRequest()->getUser();
                     $href = $user->loadEditorLink($entry['file'], $entry['line'], '');
                 } catch (Exception $ex) {
                     // The database can be inaccessible.
                 }
             }
             $details[] = phutil_tag('a', array('href' => $href), $line);
             $details[] = "\n";
         }
         $details[] = hsprintf('</div>');
     }
     $table = new AphrontTableView($rows);
     $table->setClassName('error-log');
     $table->setHeaders(array('Error'));
     $table->setNoDataString('No errors.');
     return phutil_tag('div', array(), array(phutil_tag('div', array(), $table->render()), phutil_tag('pre', array('class' => 'PhabricatorMonospaced'), $details)));
 }
 public function render()
 {
     $rows = array();
     if (!$this->user) {
         throw new Exception("Call setUser() before rendering!");
     }
     $user_phids = mpull($this->samples, 'getUserPHID');
     $users = id(new PhabricatorObjectHandleData($user_phids))->loadObjects();
     foreach ($this->samples as $sample) {
         $sample_link = phutil_render_tag('a', array('href' => '/xhprof/profile/' . $sample->getFilePHID() . '/'), $sample->getFilePHID());
         if ($this->showType) {
             if ($sample->getSampleRate() == 0) {
                 $sample_link .= ' (manual run)';
             } else {
                 $sample_link .= ' (sampled)';
             }
         }
         $rows[] = array($sample_link, phabricator_datetime($sample->getDateCreated(), $this->user), number_format($sample->getUsTotal()) . " μs", $sample->getHostname(), $sample->getRequestPath(), $sample->getController(), idx($users, $sample->getUserPHID()));
     }
     $table = new AphrontTableView($rows);
     $table->setHeaders(array('Sample', 'Date', 'Wall Time', 'Hostname', 'Request Path', 'Controller', 'User'));
     $table->setColumnClasses(array('', '', 'right', 'wide wrap', '', ''));
     return $table->render();
 }
 public function render()
 {
     $data = $this->getData();
     $out = array();
     $out[] = '<div class="dark-console-panel-header">' . '<h1>Registered Event Listeners</h1>' . '</div>';
     $rows = array();
     foreach ($data['listeners'] as $listener) {
         $rows[] = array(phutil_escape_html($listener['id']), phutil_escape_html($listener['class']));
     }
     $table = new AphrontTableView($rows);
     $table->setHeaders(array('Internal ID', 'Listener Class'));
     $table->setColumnClasses(array('', 'wide'));
     $out[] = $table->render();
     $out[] = '<div class="dark-console-panel-header">' . '<h1>Event Log</h1>' . '</div>';
     $rows = array();
     foreach ($data['events'] as $event) {
         $rows[] = array(phutil_escape_html($event['type']), $event['stopped'] ? 'STOPPED' : null);
     }
     $table = new AphrontTableView($rows);
     $table->setColumnClasses(array('wide'));
     $table->setHeaders(array('Event Type', 'Stopped'));
     $out[] = $table->render();
     return implode("\n", $out);
 }
 public function render()
 {
     $data = $this->getData();
     $sections = array('Basics' => array('Machine' => php_uname('n')));
     // NOTE: This may not be present for some SAPIs, like php-fpm.
     if (!empty($data['Server']['SERVER_ADDR'])) {
         $addr = $data['Server']['SERVER_ADDR'];
         $sections['Basics']['Host'] = $addr;
         $sections['Basics']['Hostname'] = @gethostbyaddr($addr);
     }
     $sections = array_merge($sections, $data);
     $out = array();
     foreach ($sections as $header => $map) {
         $rows = array();
         foreach ($map as $key => $value) {
             $rows[] = array(phutil_escape_html($key), phutil_escape_html(is_array($value) ? json_encode($value) : $value));
         }
         $table = new AphrontTableView($rows);
         $table->setHeaders(array($header, null));
         $table->setColumnClasses(array('header', 'wide wrap'));
         $out[] = $table->render();
     }
     return implode("\n", $out);
 }
 public function renderPanel()
 {
     $data = $this->getData();
     $out = array();
     $out[] = phutil_tag('div', array('class' => 'dark-console-panel-header'), phutil_tag('h1', array(), pht('Registered Event Listeners')));
     $rows = array();
     foreach ($data['listeners'] as $listener) {
         $rows[] = array($listener['id'], $listener['class']);
     }
     $table = new AphrontTableView($rows);
     $table->setHeaders(array(pht('Internal ID'), pht('Listener Class')));
     $table->setColumnClasses(array('', 'wide'));
     $out[] = $table->render();
     $out[] = phutil_tag('div', array('class' => 'dark-console-panel-header'), phutil_tag('h1', array(), pht('Event Log')));
     $rows = array();
     foreach ($data['events'] as $event) {
         $rows[] = array($event['type'], $event['stopped'] ? pht('STOPPED') : null);
     }
     $table = new AphrontTableView($rows);
     $table->setColumnClasses(array('wide'));
     $table->setHeaders(array(pht('Event Type'), pht('Stopped')));
     $out[] = $table->render();
     return phutil_implode_html("\n", $out);
 }
Beispiel #25
0
 public function render(AphrontRequest $request)
 {
     $user = $request->getUser();
     $plugins = $this->getEnabledPlugins();
     foreach ($plugins as $plugin) {
         $plugin->setRequest($request);
         $plugin->willShutdown();
     }
     foreach ($plugins as $plugin) {
         $plugin->didShutdown();
     }
     foreach ($plugins as $plugin) {
         $plugin->setData($plugin->generateData());
     }
     $selected = $user->getConsoleTab();
     $visible = $user->getConsoleVisible();
     if (!isset($plugins[$selected])) {
         $selected = head_key($plugins);
     }
     $tabs = array();
     foreach ($plugins as $key => $plugin) {
         $tabs[$key] = array('name' => $plugin->getName(), 'panel' => $plugin->render());
     }
     $tabs_markup = array();
     $panel_markup = array();
     foreach ($tabs as $key => $data) {
         $is_selected = $key == $selected;
         if ($is_selected) {
             $style = null;
             $tabclass = 'dark-console-tab-selected';
         } else {
             $style = 'display: none;';
             $tabclass = null;
         }
         $tabs_markup[] = javelin_render_tag('a', array('class' => "dark-console-tab {$tabclass}", 'sigil' => 'dark-console-tab', 'id' => 'dark-console-tab-' . $key), (string) $data['name']);
         $panel_markup[] = javelin_render_tag('div', array('class' => 'dark-console-panel dark-console-panel-' . $key, 'style' => $style, 'sigil' => 'dark-console-panel'), (string) $data['panel']);
     }
     $console = javelin_render_tag('table', array('class' => 'dark-console', 'sigil' => 'dark-console', 'style' => $visible ? '' : 'display: none;'), '<tr>' . '<th class="dark-console-tabs">' . implode("\n", $tabs_markup) . '</th>' . '<td>' . implode("\n", $panel_markup) . '</td>' . '</tr>');
     if (!empty($_COOKIE['phsid'])) {
         $console = str_replace($_COOKIE['phsid'], phutil_escape_html('<session-key>'), $console);
     }
     if ($request->isAjax()) {
         // for ajax this HTML gets updated on the client
         $request_history = null;
     } else {
         $request_table_header = '<div class="dark-console-panel-request-log-separator"></div>';
         $rows = array();
         $table = new AphrontTableView($rows);
         $table->setHeaders(array('Sequence', 'Type', 'URI'));
         $table->setColumnClasses(array('', '', 'wide'));
         $request_table = $request_table_header . $table->render();
         $request_history = javelin_render_tag('table', array('class' => 'dark-console dark-console-request-log', 'sigil' => 'dark-console-request-log', 'style' => $visible ? '' : 'display: none;'), '<tr>' . '<th class="dark-console-tabs">' . javelin_render_tag('a', array('class' => 'dark-console-tab dark-console-tab-selected'), 'Request Log') . '</th>' . '<td>' . javelin_render_tag('div', array('class' => 'dark-console-panel dark-console-panel-RequestLog'), $request_table) . '</td>' . '</tr>');
     }
     return "\n\n\n\n" . $console . $request_history . "\n\n\n\n";
 }
 public function render()
 {
     $drequest = $this->getDiffusionRequest();
     $viewer = $this->getUser();
     $buildables = $this->loadBuildables(mpull($this->history, 'getCommit'));
     $has_any_build = false;
     $show_revisions = PhabricatorApplication::isClassInstalledForViewer('PhabricatorDifferentialApplication', $viewer);
     $handles = $viewer->loadHandles($this->getRequiredHandlePHIDs());
     $graph = null;
     if ($this->parents) {
         $graph = $this->renderGraph();
     }
     $show_builds = PhabricatorApplication::isClassInstalledForViewer('PhabricatorHarbormasterApplication', $this->getUser());
     $rows = array();
     $ii = 0;
     foreach ($this->history as $history) {
         $epoch = $history->getEpoch();
         if ($epoch) {
             $committed = phabricator_datetime($epoch, $viewer);
         } else {
             $committed = null;
         }
         $data = $history->getCommitData();
         $author_phid = $committer = $committer_phid = null;
         if ($data) {
             $author_phid = $data->getCommitDetail('authorPHID');
             $committer_phid = $data->getCommitDetail('committerPHID');
             $committer = $data->getCommitDetail('committer');
         }
         if ($author_phid && isset($handles[$author_phid])) {
             $author = $handles[$author_phid]->renderLink();
         } else {
             $author = self::renderName($history->getAuthorName());
         }
         $different_committer = false;
         if ($committer_phid) {
             $different_committer = $committer_phid != $author_phid;
         } else {
             if ($committer != '') {
                 $different_committer = $committer != $history->getAuthorName();
             }
         }
         if ($different_committer) {
             if ($committer_phid && isset($handles[$committer_phid])) {
                 $committer = $handles[$committer_phid]->renderLink();
             } else {
                 $committer = self::renderName($committer);
             }
             $author = hsprintf('%s/%s', $author, $committer);
         }
         // We can show details once the message and change have been imported.
         $partial_import = PhabricatorRepositoryCommit::IMPORTED_MESSAGE | PhabricatorRepositoryCommit::IMPORTED_CHANGE;
         $commit = $history->getCommit();
         if ($commit && $commit->isPartiallyImported($partial_import) && $data) {
             $summary = AphrontTableView::renderSingleDisplayLine($history->getSummary());
         } else {
             $summary = phutil_tag('em', array(), pht("Importing…"));
         }
         $build = null;
         if ($show_builds) {
             $buildable = idx($buildables, $commit->getPHID());
             if ($buildable !== null) {
                 $build = $this->renderBuildable($buildable);
                 $has_any_build = true;
             }
         }
         $browse = $this->linkBrowse($history->getPath(), array('commit' => $history->getCommitIdentifier(), 'branch' => $drequest->getBranch(), 'type' => $history->getFileType()));
         $rows[] = array($graph ? $graph[$ii++] : null, $browse, self::linkCommit($drequest->getRepository(), $history->getCommitIdentifier()), $build, $commit ? self::linkRevision(idx($this->revisions, $commit->getPHID())) : null, $author, $summary, $committed);
     }
     $view = new AphrontTableView($rows);
     $view->setHeaders(array(null, null, pht('Commit'), null, null, pht('Author/Committer'), pht('Details'), pht('Committed')));
     $view->setColumnClasses(array('threads', 'nudgeright', '', 'icon', '', '', 'wide', ''));
     $view->setColumnVisibility(array($graph ? true : false, true, true, $has_any_build, $show_revisions));
     $view->setDeviceVisibility(array($graph ? true : false, true, true, true, true, false, true, false));
     return $view->render();
 }
 public function render()
 {
     $request = $this->getDiffusionRequest();
     $repository = $request->getRepository();
     $base_path = trim($request->getPath(), '/');
     if ($base_path) {
         $base_path = $base_path . '/';
     }
     $need_pull = array();
     $rows = array();
     foreach ($this->paths as $path) {
         if ($path->getFileType() == DifferentialChangeType::FILE_DIRECTORY) {
             $browse_text = $path->getPath() . '/';
             $dir_slash = '/';
             $browse_link = '<strong>' . $this->linkBrowse($base_path . $path->getPath() . $dir_slash, array('text' => $browse_text)) . '</strong>';
         } else {
             $browse_text = $path->getPath();
             $dir_slash = null;
             $browse_link = $this->linkBrowse($base_path . $path->getPath() . $dir_slash, array('text' => $browse_text));
         }
         $commit = $path->getLastModifiedCommit();
         if ($commit) {
             $dict = self::renderLastModifiedColumns($repository, $this->handles, $commit, $path->getLastCommitData());
         } else {
             $dict = array('commit' => celerity_generate_unique_node_id(), 'date' => celerity_generate_unique_node_id(), 'time' => celerity_generate_unique_node_id(), 'author' => celerity_generate_unique_node_id(), 'details' => celerity_generate_unique_node_id());
             $uri = '/diffusion/' . $repository->getCallsign() . '/lastmodified/' . $request->getBranchURIComponent($request->getBranch()) . $base_path . $path->getPath();
             if ($request->getRawCommit()) {
                 $uri .= ';' . $request->getRawCommit();
             }
             $need_pull[$uri] = $dict;
             foreach ($dict as $k => $uniq) {
                 $dict[$k] = '<span id="' . $uniq . '"></span>';
             }
         }
         $rows[] = array($this->linkHistory($base_path . $path->getPath() . $dir_slash), $browse_link, $dict['commit'], $dict['date'], $dict['time'], $dict['author'], $dict['details']);
     }
     if ($need_pull) {
         Javelin::initBehavior('diffusion-pull-lastmodified', $need_pull);
     }
     $view = new AphrontTableView($rows);
     $view->setHeaders(array('History', 'Path', 'Modified', 'Date', 'Time', 'Author', 'Details'));
     $view->setColumnClasses(array('', '', '', '', 'right', '', 'wide'));
     return $view->render();
 }
 public function render()
 {
     $rows = array();
     foreach ($this->commits as $commit) {
         $commit_name = $this->getHandle($commit->getPHID())->renderLink();
         $author_name = null;
         if ($commit->getAuthorPHID()) {
             $author_name = $this->getHandle($commit->getAuthorPHID())->renderLink();
         }
         $rows[] = array($commit_name, $author_name, phutil_escape_html($commit->getCommitData()->getSummary()), PhabricatorAuditCommitStatusConstants::getStatusName($commit->getAuditStatus()), phabricator_datetime($commit->getEpoch(), $this->user));
     }
     $table = new AphrontTableView($rows);
     $table->setHeaders(array('Commit', 'Author', 'Summary', 'Audit Status', 'Date'));
     $table->setColumnClasses(array('n', '', 'wide', '', ''));
     if ($this->noDataString) {
         $table->setNoDataString($this->noDataString);
     }
     return $table->render();
 }
 public function render()
 {
     $drequest = $this->getDiffusionRequest();
     $handles = $this->handles;
     $graph = null;
     if ($this->parents) {
         $graph = $this->renderGraph();
     }
     $show_builds = PhabricatorApplication::isClassInstalledForViewer('PhabricatorHarbormasterApplication', $this->getUser());
     $rows = array();
     $ii = 0;
     foreach ($this->history as $history) {
         $epoch = $history->getEpoch();
         if ($epoch) {
             $date = phabricator_date($epoch, $this->user);
             $time = phabricator_time($epoch, $this->user);
         } else {
             $date = null;
             $time = null;
         }
         $data = $history->getCommitData();
         $author_phid = $committer = $committer_phid = null;
         if ($data) {
             $author_phid = $data->getCommitDetail('authorPHID');
             $committer_phid = $data->getCommitDetail('committerPHID');
             $committer = $data->getCommitDetail('committer');
         }
         if ($author_phid && isset($handles[$author_phid])) {
             $author = $handles[$author_phid]->renderLink();
         } else {
             $author = self::renderName($history->getAuthorName());
         }
         $different_committer = false;
         if ($committer_phid) {
             $different_committer = $committer_phid != $author_phid;
         } else {
             if ($committer != '') {
                 $different_committer = $committer != $history->getAuthorName();
             }
         }
         if ($different_committer) {
             if ($committer_phid && isset($handles[$committer_phid])) {
                 $committer = $handles[$committer_phid]->renderLink();
             } else {
                 $committer = self::renderName($committer);
             }
             $author = hsprintf('%s/%s', $author, $committer);
         }
         // We can show details once the message and change have been imported.
         $partial_import = PhabricatorRepositoryCommit::IMPORTED_MESSAGE | PhabricatorRepositoryCommit::IMPORTED_CHANGE;
         $commit = $history->getCommit();
         if ($commit && $commit->isPartiallyImported($partial_import) && $data) {
             $summary = AphrontTableView::renderSingleDisplayLine($history->getSummary());
         } else {
             $summary = phutil_tag('em', array(), "Importing…");
         }
         $build = null;
         if ($show_builds) {
             $buildable_lookup = $this->loadBuildablesOnDemand();
             $buildable = idx($buildable_lookup, $commit->getPHID());
             if ($buildable !== null) {
                 $icon = HarbormasterBuildable::getBuildableStatusIcon($buildable->getBuildableStatus());
                 $color = HarbormasterBuildable::getBuildableStatusColor($buildable->getBuildableStatus());
                 $name = HarbormasterBuildable::getBuildableStatusName($buildable->getBuildableStatus());
                 $icon_view = id(new PHUIIconView())->setIconFont($icon . ' ' . $color);
                 $tooltip_view = javelin_tag('span', array('sigil' => 'has-tooltip', 'meta' => array('tip' => $name)), $icon_view);
                 Javelin::initBehavior('phabricator-tooltips');
                 $href_view = phutil_tag('a', array('href' => '/' . $buildable->getMonogram()), $tooltip_view);
                 $build = $href_view;
                 $has_any_build = true;
             }
         }
         $rows[] = array($graph ? $graph[$ii++] : null, self::linkCommit($drequest->getRepository(), $history->getCommitIdentifier()), $build, $commit ? self::linkRevision(idx($this->revisions, $commit->getPHID())) : null, $author, $summary, $date, $time);
     }
     $view = new AphrontTableView($rows);
     $view->setHeaders(array('', pht('Commit'), '', pht('Revision'), pht('Author/Committer'), pht('Details'), pht('Date'), pht('Time')));
     $view->setColumnClasses(array('threads', 'n', 'icon', 'n', '', 'wide', '', 'right'));
     $view->setColumnVisibility(array($graph ? true : false));
     $view->setDeviceVisibility(array($graph ? true : false, true, true, true, false, true, false, false));
     return $view->render();
 }
 private function renderStackTrace($trace)
 {
     $libraries = PhutilBootloader::getInstance()->getAllLibraries();
     // TODO: Make this configurable?
     $host = 'https://secure.phabricator.com';
     $browse = array('arcanist' => $host . '/diffusion/ARC/browse/origin:master/src/', 'phutil' => $host . '/diffusion/PHU/browse/origin:master/src/', 'phabricator' => $host . '/diffusion/P/browse/origin:master/src/');
     $rows = array();
     $depth = count($trace);
     foreach ($trace as $part) {
         $lib = null;
         $file = idx($part, 'file');
         $relative = $file;
         foreach ($libraries as $library) {
             $root = phutil_get_library_root($library);
             if (Filesystem::isDescendant($file, $root)) {
                 $lib = $library;
                 $relative = Filesystem::readablePath($file, $root);
                 break;
             }
         }
         $where = '';
         if (isset($part['class'])) {
             $where .= $part['class'] . '::';
         }
         if (isset($part['function'])) {
             $where .= $part['function'] . '()';
         }
         if ($file) {
             if (isset($browse[$lib])) {
                 $file_name = phutil_render_tag('a', array('href' => $browse[$lib] . $relative . '$' . $part['line'], 'title' => $file, 'target' => '_blank'), phutil_escape_html($relative));
             } else {
                 $file_name = phutil_render_tag('span', array('title' => $file), phutil_escape_html($relative));
             }
             $file_name = $file_name . ' : ' . (int) $part['line'];
         } else {
             $file_name = '<em>(Internal)</em>';
         }
         $rows[] = array($depth--, phutil_escape_html($lib), $file_name, phutil_escape_html($where));
     }
     $table = new AphrontTableView($rows);
     $table->setHeaders(array('Depth', 'Library', 'File', 'Where'));
     $table->setColumnClasses(array('n', '', '', 'wide'));
     return '<div class="exception-trace">' . '<div class="exception-trace-header">Stack Trace</div>' . $table->render() . '</div>';
 }