private function buildMergesTable(PhabricatorRepositoryCommit $commit)
 {
     $drequest = $this->getDiffusionRequest();
     $repository = $drequest->getRepository();
     $vcs = $repository->getVersionControlSystem();
     switch ($vcs) {
         case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
             // These aren't supported under SVN.
             return null;
     }
     $limit = 50;
     $merges = $this->callConduitWithDiffusionRequest('diffusion.mergedcommitsquery', array('commit' => $drequest->getCommit(), 'limit' => $limit + 1));
     if (!$merges) {
         return null;
     }
     $merges = DiffusionPathChange::newFromConduit($merges);
     $caption = null;
     if (count($merges) > $limit) {
         $merges = array_slice($merges, 0, $limit);
         $caption = new PHUIInfoView();
         $caption->setSeverity(PHUIInfoView::SEVERITY_NOTICE);
         $caption->appendChild(pht('This commit merges a very large number of changes. ' . 'Only the first %s are shown.', new PhutilNumber($limit)));
     }
     $history_table = new DiffusionHistoryTableView();
     $history_table->setUser($this->getRequest()->getUser());
     $history_table->setDiffusionRequest($drequest);
     $history_table->setHistory($merges);
     $history_table->loadRevisions();
     $phids = $history_table->getRequiredHandlePHIDs();
     $handles = $this->loadViewerHandles($phids);
     $history_table->setHandles($handles);
     $panel = new PHUIObjectBoxView();
     $panel->setHeaderText(pht('Merged Changes'));
     $panel->setTable($history_table);
     if ($caption) {
         $panel->setInfoView($caption);
     }
     return $panel;
 }
 public function renderBurn()
 {
     $request = $this->getRequest();
     $viewer = $request->getUser();
     $handle = null;
     $project_phid = $request->getStr('project');
     if ($project_phid) {
         $phids = array($project_phid);
         $handles = $this->loadViewerHandles($phids);
         $handle = $handles[$project_phid];
     }
     $table = new ManiphestTransaction();
     $conn = $table->establishConnection('r');
     $joins = '';
     if ($project_phid) {
         $joins = qsprintf($conn, 'JOIN %T t ON x.objectPHID = t.phid
       JOIN %T p ON p.src = t.phid AND p.type = %d AND p.dst = %s', id(new ManiphestTask())->getTableName(), PhabricatorEdgeConfig::TABLE_NAME_EDGE, PhabricatorProjectObjectHasProjectEdgeType::EDGECONST, $project_phid);
     }
     $data = queryfx_all($conn, 'SELECT x.oldValue, x.newValue, x.dateCreated FROM %T x %Q
     WHERE transactionType = %s
     ORDER BY x.dateCreated ASC', $table->getTableName(), $joins, ManiphestTransaction::TYPE_STATUS);
     $stats = array();
     $day_buckets = array();
     $open_tasks = array();
     foreach ($data as $key => $row) {
         // NOTE: Hack to avoid json_decode().
         $oldv = trim($row['oldValue'], '"');
         $newv = trim($row['newValue'], '"');
         if ($oldv == 'null') {
             $old_is_open = false;
         } else {
             $old_is_open = ManiphestTaskStatus::isOpenStatus($oldv);
         }
         $new_is_open = ManiphestTaskStatus::isOpenStatus($newv);
         $is_open = $new_is_open && !$old_is_open;
         $is_close = $old_is_open && !$new_is_open;
         $data[$key]['_is_open'] = $is_open;
         $data[$key]['_is_close'] = $is_close;
         if (!$is_open && !$is_close) {
             // This is either some kind of bogus event, or a resolution change
             // (e.g., resolved -> invalid). Just skip it.
             continue;
         }
         $day_bucket = phabricator_format_local_time($row['dateCreated'], $viewer, 'Yz');
         $day_buckets[$day_bucket] = $row['dateCreated'];
         if (empty($stats[$day_bucket])) {
             $stats[$day_bucket] = array('open' => 0, 'close' => 0);
         }
         $stats[$day_bucket][$is_close ? 'close' : 'open']++;
     }
     $template = array('open' => 0, 'close' => 0);
     $rows = array();
     $rowc = array();
     $last_month = null;
     $last_month_epoch = null;
     $last_week = null;
     $last_week_epoch = null;
     $week = null;
     $month = null;
     $last = last_key($stats) - 1;
     $period = $template;
     foreach ($stats as $bucket => $info) {
         $epoch = $day_buckets[$bucket];
         $week_bucket = phabricator_format_local_time($epoch, $viewer, 'YW');
         if ($week_bucket != $last_week) {
             if ($week) {
                 $rows[] = $this->formatBurnRow(pht('Week of %s', phabricator_date($last_week_epoch, $viewer)), $week);
                 $rowc[] = 'week';
             }
             $week = $template;
             $last_week = $week_bucket;
             $last_week_epoch = $epoch;
         }
         $month_bucket = phabricator_format_local_time($epoch, $viewer, 'Ym');
         if ($month_bucket != $last_month) {
             if ($month) {
                 $rows[] = $this->formatBurnRow(phabricator_format_local_time($last_month_epoch, $viewer, 'F, Y'), $month);
                 $rowc[] = 'month';
             }
             $month = $template;
             $last_month = $month_bucket;
             $last_month_epoch = $epoch;
         }
         $rows[] = $this->formatBurnRow(phabricator_date($epoch, $viewer), $info);
         $rowc[] = null;
         $week['open'] += $info['open'];
         $week['close'] += $info['close'];
         $month['open'] += $info['open'];
         $month['close'] += $info['close'];
         $period['open'] += $info['open'];
         $period['close'] += $info['close'];
     }
     if ($week) {
         $rows[] = $this->formatBurnRow(pht('Week To Date'), $week);
         $rowc[] = 'week';
     }
     if ($month) {
         $rows[] = $this->formatBurnRow(pht('Month To Date'), $month);
         $rowc[] = 'month';
     }
     $rows[] = $this->formatBurnRow(pht('All Time'), $period);
     $rowc[] = 'aggregate';
     $rows = array_reverse($rows);
     $rowc = array_reverse($rowc);
     $table = new AphrontTableView($rows);
     $table->setRowClasses($rowc);
     $table->setHeaders(array(pht('Period'), pht('Opened'), pht('Closed'), pht('Change')));
     $table->setColumnClasses(array('right wide', 'n', 'n', 'n'));
     if ($handle) {
         $inst = pht('NOTE: This table reflects tasks currently in ' . 'the project. If a task was opened in the past but added to ' . 'the project recently, it is counted on the day it was ' . 'opened, not the day it was categorized. If a task was part ' . 'of this project in the past but no longer is, it is not ' . 'counted at all.');
         $header = pht('Task Burn Rate for Project %s', $handle->renderLink());
         $caption = phutil_tag('p', array(), $inst);
     } else {
         $header = pht('Task Burn Rate for All Tasks');
         $caption = null;
     }
     if ($caption) {
         $caption = id(new PHUIInfoView())->appendChild($caption)->setSeverity(PHUIInfoView::SEVERITY_NOTICE);
     }
     $panel = new PHUIObjectBoxView();
     $panel->setHeaderText($header);
     if ($caption) {
         $panel->setInfoView($caption);
     }
     $panel->setTable($table);
     $tokens = array();
     if ($handle) {
         $tokens = array($handle);
     }
     $filter = $this->renderReportFilters($tokens, $has_window = false);
     $id = celerity_generate_unique_node_id();
     $chart = phutil_tag('div', array('id' => $id, 'style' => 'border: 1px solid #BFCFDA; ' . 'background-color: #fff; ' . 'margin: 8px 16px; ' . 'height: 400px; '), '');
     list($burn_x, $burn_y) = $this->buildSeries($data);
     require_celerity_resource('d3');
     require_celerity_resource('phui-chart-css');
     Javelin::initBehavior('line-chart', array('hardpoint' => $id, 'x' => array($burn_x), 'y' => array($burn_y), 'xformat' => 'epoch', 'yformat' => 'int'));
     $box = id(new PHUIObjectBoxView())->setHeaderText(pht('Burnup Rate'))->appendChild($chart);
     return array($filter, $box, $panel);
 }
 public function handleRequest(AphrontRequest $request)
 {
     $uri = $request->getStr('uri');
     $id = $request->getStr('id');
     $repositories = id(new PhabricatorRepositoryQuery())->setViewer($request->getUser())->execute();
     if ($uri) {
         $uri_path = id(new PhutilURI($uri))->getPath();
         $matches = array();
         // Try to figure out which tracked repository this external lives in by
         // comparing repository metadata. We look for an exact match, but accept
         // a partial match.
         foreach ($repositories as $key => $repository) {
             $remote_uri = new PhutilURI($repository->getRemoteURI());
             if ($remote_uri->getPath() == $uri_path) {
                 $matches[$key] = 1;
             }
             if ($repository->getPublicCloneURI() == $uri) {
                 $matches[$key] = 2;
             }
             if ($repository->getRemoteURI() == $uri) {
                 $matches[$key] = 3;
             }
         }
         arsort($matches);
         $best_match = head_key($matches);
         if ($best_match) {
             $repository = $repositories[$best_match];
             $redirect = $repository->generateURI(array('action' => 'browse', 'branch' => $repository->getDefaultBranch(), 'commit' => $id));
             return id(new AphrontRedirectResponse())->setURI($redirect);
         }
     }
     // TODO: This is a rare query but does a table scan, add a key?
     $commits = id(new PhabricatorRepositoryCommit())->loadAllWhere('commitIdentifier = %s', $id);
     if (empty($commits)) {
         $desc = null;
         if (strlen($uri)) {
             $desc = pht('"%s", at "%s"', $uri, $id);
         } else {
             $desc = pht('"%s"', $id);
         }
         $content = id(new PHUIInfoView())->setTitle(pht('Unknown External'))->setSeverity(PHUIInfoView::SEVERITY_WARNING)->appendChild(phutil_tag('p', array(), pht('This external (%s) does not appear in any tracked ' . 'repository. It may exist in an untracked repository that ' . 'Diffusion does not know about.', $desc)));
     } else {
         if (count($commits) == 1) {
             $commit = head($commits);
             $repo = $repositories[$commit->getRepositoryID()];
             $redirect = $repo->generateURI(array('action' => 'browse', 'branch' => $repo->getDefaultBranch(), 'commit' => $commit->getCommitIdentifier()));
             return id(new AphrontRedirectResponse())->setURI($redirect);
         } else {
             $rows = array();
             foreach ($commits as $commit) {
                 $repo = $repositories[$commit->getRepositoryID()];
                 $href = $repo->generateURI(array('action' => 'browse', 'branch' => $repo->getDefaultBranch(), 'commit' => $commit->getCommitIdentifier()));
                 $rows[] = array(phutil_tag('a', array('href' => $href), $commit->getURI()), $commit->loadCommitData()->getSummary());
             }
             $table = new AphrontTableView($rows);
             $table->setHeaders(array(pht('Commit'), pht('Description')));
             $table->setColumnClasses(array('pri', 'wide'));
             $caption = id(new PHUIInfoView())->setSeverity(PHUIInfoView::SEVERITY_NOTICE)->appendChild(pht('This external reference matches multiple known commits.'));
             $content = new PHUIObjectBoxView();
             $content->setHeaderText(pht('Multiple Matching Commits'));
             $content->setInfoView($caption);
             $content->setTable($table);
         }
     }
     $crumbs = $this->buildApplicationCrumbs();
     $crumbs->addTextCrumb(pht('External'));
     return $this->newPage()->setTitle(pht('Unresolvable External'))->setCrumbs($crumbs)->appendChild($content);
 }
 private function buildMergesTable(PhabricatorRepositoryCommit $commit)
 {
     $viewer = $this->getViewer();
     $drequest = $this->getDiffusionRequest();
     $repository = $drequest->getRepository();
     $merges = $this->getCommitMerges();
     if (!$merges) {
         return null;
     }
     $limit = $this->getMergeDisplayLimit();
     $caption = null;
     if (count($merges) > $limit) {
         $merges = array_slice($merges, 0, $limit);
         $caption = new PHUIInfoView();
         $caption->setSeverity(PHUIInfoView::SEVERITY_NOTICE);
         $caption->appendChild(pht('This commit merges a very large number of changes. ' . 'Only the first %s are shown.', new PhutilNumber($limit)));
     }
     $history_table = id(new DiffusionHistoryTableView())->setUser($viewer)->setDiffusionRequest($drequest)->setHistory($merges);
     $history_table->loadRevisions();
     $panel = new PHUIObjectBoxView();
     $panel->setHeaderText(pht('Merged Changes'));
     $panel->setTable($history_table);
     if ($caption) {
         $panel->setInfoView($caption);
     }
     return $panel;
 }
Ejemplo n.º 5
0
 protected function addLockMessage(PHUIObjectBoxView $box, $message)
 {
     $doc_link = phutil_tag('a', array('href' => PhabricatorEnv::getDoclink('Almanac User Guide'), 'target' => '_blank'), pht('Learn More'));
     $error_view = id(new PHUIInfoView())->setSeverity(PHUIInfoView::SEVERITY_WARNING)->setErrors(array(array($message, ' ', $doc_link)));
     $box->setInfoView($error_view);
 }
 private function buildStatsTable()
 {
     $handle = null;
     $project_phid = $this->request->getStr('project');
     if ($project_phid) {
         $phids = array($project_phid);
         $handle = $this->getProjectHandle($phids, $project_phid, $this->request);
     }
     $data = $this->getXactionData($project_phid);
     $stats = $this->buildStatsfromEvents($data);
     $day_buckets = $this->buildDayBucketsfromEvents($data);
     list($rows, $rowc, $week, $month, $period) = $this->formatBucketRows($stats, $day_buckets);
     list($rows, $rowc) = $this->formatStatsTableHeaders($week, $month, $period, $rows, $rowc);
     $table = $this->statsTableView($rows, $rowc);
     if ($handle) {
         list($caption, $header) = $this->renderCaption($handle);
         $caption = id(new PHUIInfoView())->appendChild($caption)->setSeverity(PHUIInfoView::SEVERITY_NOTICE);
     } else {
         $header = pht('Task Burn Rate for All Tasks');
         $caption = null;
     }
     $panel = new PHUIObjectBoxView();
     $panel->setHeaderText($header);
     if ($caption) {
         $panel->setInfoView($caption);
     }
     $panel->setTable($table);
     return $panel;
 }