diff --git a/src/applications/diffusion/controller/DiffusionBrowseController.php b/src/applications/diffusion/controller/DiffusionBrowseController.php index 963840bf64..646acb2c39 100644 --- a/src/applications/diffusion/controller/DiffusionBrowseController.php +++ b/src/applications/diffusion/controller/DiffusionBrowseController.php @@ -1,134 +1,135 @@ diffusionRequest; $browse_query = DiffusionBrowseQuery::newFromDiffusionRequest($drequest); $results = $browse_query->loadPaths(); $content = array(); $content[] = $this->buildCrumbs( array( 'branch' => true, 'path' => true, 'view' => 'browse', )); if ($drequest->getTagContent()) { $title = 'Tag: '.$drequest->getSymbolicCommit(); $tag_view = new AphrontPanelView(); $tag_view->setHeader(phutil_escape_html($title)); $tag_view->appendChild( $this->markupText($drequest->getTagContent())); $content[] = $tag_view; } if (!$results) { if ($browse_query->getReasonForEmptyResultSet() == DiffusionBrowseQuery::REASON_IS_FILE) { $controller = new DiffusionBrowseFileController($this->getRequest()); $controller->setDiffusionRequest($drequest); return $this->delegateToController($controller); } $empty_result = new DiffusionEmptyResultView(); $empty_result->setDiffusionRequest($drequest); $empty_result->setBrowseQuery($browse_query); $empty_result->setView($this->getRequest()->getStr('view')); $content[] = $empty_result; } else { $readme = null; $phids = array(); foreach ($results as $result) { $data = $result->getLastCommitData(); if ($data) { if ($data->getCommitDetail('authorPHID')) { $phids[$data->getCommitDetail('authorPHID')] = true; } } $path = $result->getPath(); if (preg_match('/^readme(|\.txt|\.remarkup)$/i', $path)) { $readme = $result; } } $phids = array_keys($phids); $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles(); $browse_table = new DiffusionBrowseTableView(); $browse_table->setDiffusionRequest($drequest); $browse_table->setHandles($handles); $browse_table->setPaths($results); + $browse_table->setUser($this->getRequest()->getUser()); $browse_panel = new AphrontPanelView(); $browse_panel->appendChild($browse_table); $content[] = $browse_panel; } $content[] = $this->buildOpenRevisions(); $readme_content = $browse_query->renderReadme($results); if ($readme_content) { $readme_panel = new AphrontPanelView(); $readme_panel->setHeader('README'); $readme_panel->appendChild($readme_content); $content[] = $readme_panel; } $nav = $this->buildSideNav('browse', false); $nav->appendChild($content); return $this->buildStandardPageResponse( $nav, array( 'title' => array( nonempty(basename($drequest->getPath()), '/'), $drequest->getRepository()->getCallsign().' Repository', ), )); } private function markupText($text) { $engine = PhabricatorMarkupEngine::newDiffusionMarkupEngine(); $text = $engine->markupText($text); $text = phutil_render_tag( 'div', array( 'class' => 'phabricator-remarkup', ), $text); return $text; } } diff --git a/src/applications/diffusion/controller/DiffusionRepositoryController.php b/src/applications/diffusion/controller/DiffusionRepositoryController.php index 5af5cc6bf6..ee373c5ccc 100644 --- a/src/applications/diffusion/controller/DiffusionRepositoryController.php +++ b/src/applications/diffusion/controller/DiffusionRepositoryController.php @@ -1,268 +1,269 @@ diffusionRequest; $content = array(); $crumbs = $this->buildCrumbs(); $content[] = $crumbs; $content[] = $this->buildPropertiesTable($drequest->getRepository()); $history_query = DiffusionHistoryQuery::newFromDiffusionRequest( $drequest); $history_query->setLimit(15); $history_query->needParents(true); $history = $history_query->loadHistory(); $browse_query = DiffusionBrowseQuery::newFromDiffusionRequest($drequest); $browse_results = $browse_query->loadPaths(); $phids = array(); foreach ($history as $item) { $data = $item->getCommitData(); if ($data) { if ($data->getCommitDetail('authorPHID')) { $phids[$data->getCommitDetail('authorPHID')] = true; } if ($data->getCommitDetail('committerPHID')) { $phids[$data->getCommitDetail('committerPHID')] = true; } } } foreach ($browse_results as $item) { $data = $item->getLastCommitData(); if ($data) { if ($data->getCommitDetail('authorPHID')) { $phids[$data->getCommitDetail('authorPHID')] = true; } if ($data->getCommitDetail('committerPHID')) { $phids[$data->getCommitDetail('committerPHID')] = true; } } } $phids = array_keys($phids); $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles(); $history_table = new DiffusionHistoryTableView(); $history_table->setDiffusionRequest($drequest); $history_table->setHandles($handles); $history_table->setHistory($history); $history_table->loadRevisions(); $history_table->setParents($history_query->getParents()); $history_table->setIsHead(true); $callsign = $drequest->getRepository()->getCallsign(); $all = phutil_render_tag( 'a', array( 'href' => "/diffusion/{$callsign}/history/", ), 'View Full Commit History'); $panel = new AphrontPanelView(); $panel->setHeader("Recent Commits · {$all}"); $panel->appendChild($history_table); $content[] = $panel; $browse_table = new DiffusionBrowseTableView(); $browse_table->setDiffusionRequest($drequest); $browse_table->setHandles($handles); $browse_table->setPaths($browse_results); + $browse_table->setUser($this->getRequest()->getUser()); $browse_panel = new AphrontPanelView(); $browse_panel->setHeader('Browse Repository'); $browse_panel->appendChild($browse_table); $content[] = $browse_panel; $content[] = $this->buildTagListTable($drequest); $content[] = $this->buildBranchListTable($drequest); $readme = $browse_query->renderReadme($browse_results); if ($readme) { $panel = new AphrontPanelView(); $panel->setHeader('README'); $panel->appendChild($readme); $content[] = $panel; } return $this->buildStandardPageResponse( $content, array( 'title' => $drequest->getRepository()->getName(), )); } private function buildPropertiesTable(PhabricatorRepository $repository) { $properties = array(); $properties['Name'] = $repository->getName(); $properties['Callsign'] = $repository->getCallsign(); $properties['Description'] = $repository->getDetail('description'); switch ($repository->getVersionControlSystem()) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: $properties['Clone URI'] = $repository->getPublicRemoteURI(); break; case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: $properties['Repository Root'] = $repository->getPublicRemoteURI(); break; } $rows = array(); foreach ($properties as $key => $value) { $rows[] = array( phutil_escape_html($key), phutil_escape_html($value)); } $table = new AphrontTableView($rows); $table->setColumnClasses( array( 'header', 'wide', )); $panel = new AphrontPanelView(); $panel->setHeader('Repository Properties'); $panel->appendChild($table); return $panel; } private function buildBranchListTable(DiffusionRequest $drequest) { if ($drequest->getBranch() !== null) { $limit = 15; $branch_query = DiffusionBranchQuery::newFromDiffusionRequest($drequest); $branch_query->setLimit($limit + 1); $branches = $branch_query->loadBranches(); if (!$branches) { return null; } $more_branches = (count($branches) > $limit); $branches = array_slice($branches, 0, $limit); $commits = id(new PhabricatorAuditCommitQuery()) ->withIdentifiers( $drequest->getRepository()->getID(), mpull($branches, 'getHeadCommitIdentifier')) ->needCommitData(true) ->execute(); $table = new DiffusionBranchTableView(); $table->setDiffusionRequest($drequest); $table->setBranches($branches); $table->setCommits($commits); $table->setUser($this->getRequest()->getUser()); $panel = new AphrontPanelView(); $panel->setHeader('Branches'); if ($more_branches) { $panel->setCaption('Showing ' . $limit . ' branches.'); } $panel->addButton( phutil_render_tag( 'a', array( 'href' => $drequest->generateURI( array( 'action' => 'branches', )), 'class' => 'grey button', ), "Show All Branches \xC2\xBB")); $panel->appendChild($table); return $panel; } return null; } private function buildTagListTable(DiffusionRequest $drequest) { $tag_limit = 15; $query = DiffusionTagListQuery::newFromDiffusionRequest($drequest); $query->setLimit($tag_limit + 1); $tags = $query->loadTags(); if (!$tags) { return null; } $more_tags = (count($tags) > $tag_limit); $tags = array_slice($tags, 0, $tag_limit); $commits = id(new PhabricatorAuditCommitQuery()) ->withIdentifiers( $drequest->getRepository()->getID(), mpull($tags, 'getCommitIdentifier')) ->needCommitData(true) ->execute(); $view = new DiffusionTagListView(); $view->setDiffusionRequest($drequest); $view->setTags($tags); $view->setUser($this->getRequest()->getUser()); $view->setCommits($commits); $phids = $view->getRequiredHandlePHIDs(); $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles(); $view->setHandles($handles); $panel = new AphrontPanelView(); $panel->setHeader('Tags'); if ($more_tags) { $panel->setCaption('Showing the '.$tag_limit.' most recent tags.'); } $panel->addButton( phutil_render_tag( 'a', array( 'href' => $drequest->generateURI( array( 'action' => 'tags', )), 'class' => 'grey button', ), "Show All Tags \xC2\xBB")); $panel->appendChild($view); return $panel; } } diff --git a/src/applications/diffusion/view/DiffusionBrowseTableView.php b/src/applications/diffusion/view/DiffusionBrowseTableView.php index ecbf6e03ce..b185d8cd17 100644 --- a/src/applications/diffusion/view/DiffusionBrowseTableView.php +++ b/src/applications/diffusion/view/DiffusionBrowseTableView.php @@ -1,241 +1,280 @@ paths = $paths; return $this; } public function setHandles(array $handles) { assert_instances_of($handles, 'PhabricatorObjectHandle'); $this->handles = $handles; return $this; } private static function renderName($name) { $email = new PhutilEmailAddress($name); if ($email->getDisplayName() || $email->getDomainName()) { return phutil_render_tag( 'span', array( 'title' => $email->getAddress(), ), phutil_escape_html($email->getDisplayName())); } return phutil_escape_html($name); } + public function setUser(PhabricatorUser $user) { + $this->user = $user; + return $this; + } + public static function renderLastModifiedColumns( PhabricatorRepository $repository, array $handles, PhabricatorRepositoryCommit $commit = null, PhabricatorRepositoryCommitData $data = null) { assert_instances_of($handles, 'PhabricatorObjectHandle'); if ($commit) { $epoch = $commit->getEpoch(); $modified = DiffusionView::linkCommit( $repository, $commit->getCommitIdentifier()); $date = date('M j, Y', $epoch); $time = date('g:i A', $epoch); } else { $modified = ''; $date = ''; $time = ''; } if ($data) { $author_phid = $data->getCommitDetail('authorPHID'); if ($author_phid && isset($handles[$author_phid])) { $author = $handles[$author_phid]->renderLink(); } else { $author = self::renderName($data->getAuthorName()); } $committer = $data->getCommitDetail('committer'); if ($committer) { $committer_phid = $data->getCommitDetail('committerPHID'); if ($committer_phid && isset($handles[$committer_phid])) { $committer = $handles[$committer_phid]->renderLink(); } else { $committer = self::renderName($data->getCommitDetail('committer')); } } else { $committer = $author; } $details = AphrontTableView::renderSingleDisplayLine( phutil_escape_html($data->getSummary())); } else { $author = ''; $details = ''; $committer = ''; } return array( 'commit' => $modified, 'date' => $date, 'time' => $time, 'author' => $author, 'committer' => $committer, 'details' => $details, ); } 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) { $dir_slash = null; $file_type = $path->getFileType(); if ($file_type == DifferentialChangeType::FILE_DIRECTORY) { $browse_text = $path->getPath().'/'; $dir_slash = '/'; $browse_link = ''.$this->linkBrowse( $base_path.$path->getPath().$dir_slash, array( 'html' => $this->renderPathIcon( 'dir', $browse_text), )).''; } else if ($file_type == DifferentialChangeType::FILE_SUBMODULE) { $browse_text = $path->getPath().'/'; $browse_link = ''. $this->linkExternal( $path->getHash(), $path->getExternalURI(), $this->renderPathIcon( 'ext', $browse_text)). ''; } else { if ($file_type == DifferentialChangeType::FILE_SYMLINK) { $type = 'link'; } else { $type = 'file'; } $browse_text = $path->getPath(); $browse_link = $this->linkBrowse( $base_path.$path->getPath(), array( 'html' => $this->renderPathIcon($type, $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(), 'committer' => celerity_generate_unique_node_id(), 'details' => celerity_generate_unique_node_id(), ); $uri = (string)$request->generateURI( array( 'action' => 'lastmodified', 'path' => $base_path.$path->getPath(), )); $need_pull[$uri] = $dict; foreach ($dict as $k => $uniq) { $dict[$k] = ''; } } + $editor_button = ''; + if ($this->user) { + $editor_link = $this->user->loadEditorLink( + $base_path.$path->getPath(), + 1, + $request->getRepository()->getCallsign()); + if ($editor_link) { + $show_edit = true; + $editor_button = phutil_render_tag( + 'a', + array( + 'href' => $editor_link, + ), + 'Edit'); + } + } + $rows[] = array( $this->linkHistory($base_path.$path->getPath().$dir_slash), + $editor_button, $browse_link, $dict['commit'], $dict['date'], $dict['time'], $dict['author'], $dict['committer'], $dict['details'], ); } if ($need_pull) { Javelin::initBehavior('diffusion-pull-lastmodified', $need_pull); } $view = new AphrontTableView($rows); $view->setHeaders( array( 'History', + 'Edit', 'Path', 'Modified', 'Date', 'Time', 'Author', 'Committer', 'Details', )); $view->setColumnClasses( array( '', '', '', '', + '', 'right', '', '', 'wide', )); + $view->setColumnVisibility( + array( + true, + $show_edit, + true, + true, + true, + true, + true, + true, + true, + )); return $view->render(); } private function renderPathIcon($type, $text) { require_celerity_resource('diffusion-icons-css'); return phutil_render_tag( 'span', array( 'class' => 'diffusion-path-icon diffusion-path-icon-'.$type, ), phutil_escape_html($text)); } }