public function render() { $viewer = $this->getUser(); if (!$viewer) { throw new PhutilInvalidStateException('setUser'); } require_celerity_resource('conpherence-transaction-css'); $transaction = $this->getConpherenceTransaction(); switch ($transaction->getTransactionType()) { case ConpherenceTransaction::TYPE_DATE_MARKER: return javelin_tag('div', array('class' => 'conpherence-transaction-view date-marker', 'sigil' => 'conpherence-transaction-view', 'meta' => array('id' => $transaction->getID() + 0.5)), array(phutil_tag('span', array('class' => 'date'), phabricator_format_local_time($transaction->getDateCreated(), $viewer, 'M jS, Y')))); break; } $info = $this->renderTransactionInfo(); $actions = $this->renderTransactionActions(); $image = $this->renderTransactionImage(); $content = $this->renderTransactionContent(); $classes = implode(' ', $this->classes); $transaction_dom_id = null; if ($this->getFullDisplay()) { $transaction_dom_id = 'anchor-' . $transaction->getID(); } $header = phutil_tag_div('conpherence-transaction-header grouped', array($actions, $info)); return javelin_tag('div', array('class' => 'conpherence-transaction-view ' . $classes, 'id' => $transaction_dom_id, 'sigil' => 'conpherence-transaction-view', 'meta' => array('id' => $transaction->getID())), array($image, phutil_tag_div('conpherence-transaction-detail grouped', array($header, $content)))); }
public function processRequest() { $now = time(); $request = $this->getRequest(); $user = $request->getUser(); $year_d = phabricator_format_local_time($now, $user, 'Y'); $year = $request->getInt('year', $year_d); $month_d = phabricator_format_local_time($now, $user, 'm'); $month = $request->getInt('month', $month_d); $day = phabricator_format_local_time($now, $user, 'j'); $holidays = id(new PhabricatorCalendarHoliday())->loadAllWhere('day BETWEEN %s AND %s', "{$year}-{$month}-01", "{$year}-{$month}-31"); $statuses = id(new PhabricatorCalendarEventQuery())->setViewer($user)->withDateRange(strtotime("{$year}-{$month}-01"), strtotime("{$year}-{$month}-01 next month"))->execute(); if ($month == $month_d && $year == $year_d) { $month_view = new PHUICalendarMonthView($month, $year, $day); } else { $month_view = new PHUICalendarMonthView($month, $year); } $month_view->setBrowseURI($request->getRequestURI()); $month_view->setUser($user); $month_view->setHolidays($holidays); $phids = mpull($statuses, 'getUserPHID'); $handles = $this->loadViewerHandles($phids); /* Assign Colors */ $unique = array_unique($phids); $allblue = false; $calcolors = CalendarColors::getColors(); if (count($unique) > count($calcolors)) { $allblue = true; } $i = 0; $eventcolor = array(); foreach ($unique as $phid) { if ($allblue) { $eventcolor[$phid] = CalendarColors::COLOR_SKY; } else { $eventcolor[$phid] = $calcolors[$i]; } $i++; } foreach ($statuses as $status) { $event = new AphrontCalendarEventView(); $event->setEpochRange($status->getDateFrom(), $status->getDateTo()); $name_text = $handles[$status->getUserPHID()]->getName(); $status_text = $status->getHumanStatus(); $event->setUserPHID($status->getUserPHID()); $event->setDescription(pht('%s (%s)', $name_text, $status_text)); $event->setName($status_text); $event->setEventID($status->getID()); $event->setColor($eventcolor[$status->getUserPHID()]); $month_view->addEvent($event); } $date = new DateTime("{$year}-{$month}-01"); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('All Events')); $crumbs->addTextCrumb($date->format('F Y')); $nav = $this->buildSideNavView(); $nav->selectFilter('all/'); $nav->appendChild(array($crumbs, $month_view)); return $this->buildApplicationPage($nav, array('title' => pht('Calendar'))); }
public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); $username = $request->getURIData('username'); $user = id(new PhabricatorPeopleQuery())->setViewer($viewer)->withUsernames(array($username))->needProfileImage(true)->executeOne(); if (!$user) { return new Aphront404Response(); } $this->setUser($user); $picture = $user->getProfileImageURI(); $now = time(); $request = $this->getRequest(); $year_d = phabricator_format_local_time($now, $user, 'Y'); $year = $request->getInt('year', $year_d); $month_d = phabricator_format_local_time($now, $user, 'm'); $month = $request->getInt('month', $month_d); $day = phabricator_format_local_time($now, $user, 'j'); $start_epoch = strtotime("{$year}-{$month}-01"); $end_epoch = strtotime("{$year}-{$month}-01 next month"); $statuses = id(new PhabricatorCalendarEventQuery())->setViewer($user)->withInvitedPHIDs(array($user->getPHID()))->withDateRange($start_epoch, $end_epoch)->execute(); $start_range_value = AphrontFormDateControlValue::newFromEpoch($user, $start_epoch); $end_range_value = AphrontFormDateControlValue::newFromEpoch($user, $end_epoch); if ($month == $month_d && $year == $year_d) { $month_view = new PHUICalendarMonthView($start_range_value, $end_range_value, $month, $year, $day); } else { $month_view = new PHUICalendarMonthView($start_range_value, $end_range_value, $month, $year); } $month_view->setBrowseURI($request->getRequestURI()); $month_view->setUser($user); $month_view->setImage($picture); $phids = mpull($statuses, 'getUserPHID'); $handles = $this->loadViewerHandles($phids); foreach ($statuses as $status) { $event = new AphrontCalendarEventView(); $event->setEpochRange($status->getDateFrom(), $status->getDateTo()); $event->setUserPHID($status->getUserPHID()); $event->setName($status->getName()); $event->setDescription($status->getDescription()); $event->setEventID($status->getID()); $month_view->addEvent($event); } $nav = $this->getProfileMenu(); $nav->selectFilter('calendar'); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Calendar')); return $this->newPage()->setTitle(pht('Calendar'))->setNavigation($nav)->setCrumbs($crumbs)->appendChild($month_view); }
protected function renderConpherenceTransactions(ConpherenceThread $conpherence) { $user = $this->getRequest()->getUser(); $transactions = $conpherence->getTransactions(); $oldest_transaction_id = 0; $too_many = ConpherenceThreadQuery::TRANSACTION_LIMIT + 1; if (count($transactions) == $too_many) { $last_transaction = end($transactions); unset($transactions[$last_transaction->getID()]); $oldest_transaction = end($transactions); $oldest_transaction_id = $oldest_transaction->getID(); } $transactions = array_reverse($transactions); $handles = $conpherence->getHandles(); $rendered_transactions = array(); $engine = id(new PhabricatorMarkupEngine())->setViewer($user); foreach ($transactions as $key => $transaction) { if ($transaction->shouldHide()) { unset($transactions[$key]); continue; } if ($transaction->getComment()) { $engine->addObject($transaction->getComment(), PhabricatorApplicationTransactionComment::MARKUP_FIELD_COMMENT); } } $engine->process(); // we're going to insert a dummy date marker transaction for breaks // between days. some setup required! $previous_transaction = null; $date_marker_transaction = id(new ConpherenceTransaction())->setTransactionType(ConpherenceTransactionType::TYPE_DATE_MARKER)->makeEphemeral(); $date_marker_transaction_view = id(new ConpherenceTransactionView())->setUser($user)->setConpherenceTransaction($date_marker_transaction)->setHandles($handles)->setMarkupEngine($engine); foreach ($transactions as $transaction) { if ($previous_transaction) { $previous_day = phabricator_format_local_time($previous_transaction->getDateCreated(), $user, 'Ymd'); $current_day = phabricator_format_local_time($transaction->getDateCreated(), $user, 'Ymd'); // date marker transaction time! if ($previous_day != $current_day) { $date_marker_transaction->setDateCreated($transaction->getDateCreated()); $rendered_transactions[] = $date_marker_transaction_view->render(); } } $rendered_transactions[] = id(new ConpherenceTransactionView())->setUser($user)->setConpherenceTransaction($transaction)->setHandles($handles)->setMarkupEngine($engine)->render(); $previous_transaction = $transaction; } $latest_transaction_id = $transaction->getID(); return array('transactions' => $rendered_transactions, 'latest_transaction_id' => $latest_transaction_id, 'oldest_transaction_id' => $oldest_transaction_id); }
public function processRequest() { $viewer = $this->getRequest()->getUser(); $user = id(new PhabricatorPeopleQuery())->setViewer($viewer)->withUsernames(array($this->username))->needProfileImage(true)->executeOne(); if (!$user) { return new Aphront404Response(); } $picture = $user->loadProfileImageURI(); $now = time(); $request = $this->getRequest(); $year_d = phabricator_format_local_time($now, $user, 'Y'); $year = $request->getInt('year', $year_d); $month_d = phabricator_format_local_time($now, $user, 'm'); $month = $request->getInt('month', $month_d); $day = phabricator_format_local_time($now, $user, 'j'); $holidays = id(new PhabricatorCalendarHoliday())->loadAllWhere('day BETWEEN %s AND %s', "{$year}-{$month}-01", "{$year}-{$month}-31"); $statuses = id(new PhabricatorCalendarEventQuery())->setViewer($user)->withInvitedPHIDs(array($user->getPHID()))->withDateRange(strtotime("{$year}-{$month}-01"), strtotime("{$year}-{$month}-01 next month"))->execute(); if ($month == $month_d && $year == $year_d) { $month_view = new PHUICalendarMonthView($month, $year, $day); } else { $month_view = new PHUICalendarMonthView($month, $year); } $month_view->setBrowseURI($request->getRequestURI()); $month_view->setUser($user); $month_view->setHolidays($holidays); $month_view->setImage($picture); $phids = mpull($statuses, 'getUserPHID'); $handles = $this->loadViewerHandles($phids); foreach ($statuses as $status) { $event = new AphrontCalendarEventView(); $event->setEpochRange($status->getDateFrom(), $status->getDateTo()); $event->setUserPHID($status->getUserPHID()); $event->setName($status->getHumanStatus()); $event->setDescription($status->getDescription()); $event->setEventID($status->getID()); $month_view->addEvent($event); } $date = new DateTime("{$year}-{$month}-01"); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($user->getUsername(), '/p/' . $user->getUsername() . '/'); $crumbs->addTextCrumb($date->format('F Y')); return $this->buildApplicationPage(array($crumbs, $month_view), array('title' => pht('Calendar'))); }
public function parseEvents($dates) { $sprintpoints = id(new SprintPoints())->setTaskPoints($this->taskpoints); foreach ($this->events as $event) { $modify_date = $event['modified']; $task_phid = $event['objectPHID']; $points = $sprintpoints->getTaskPoints($task_phid); $date = phabricator_format_local_time($modify_date, $this->viewer, 'D M j'); switch ($event['type']) { case 'close': $this->closeTasksToday($date, $dates); $this->closePointsToday($date, $points, $dates); break; case 'reopen': $this->reopenedTasksToday($date, $dates); $this->reopenedPointsToday($date, $points, $dates); break; } } return $dates; }
public function render() { $user = $this->getUser(); $transaction = $this->getConpherenceTransaction(); switch ($transaction->getTransactionType()) { case ConpherenceTransactionType::TYPE_DATE_MARKER: return phutil_tag('div', array('class' => 'date-marker'), array(phutil_tag('span', array('class' => 'date'), phabricator_format_local_time($transaction->getDateCreated(), $user, 'M jS, Y')))); break; } $handles = $this->getHandles(); $transaction->setHandles($handles); $author = $handles[$transaction->getAuthorPHID()]; $transaction_view = id(new PhabricatorTransactionView())->setUser($user)->setEpoch($transaction->getDateCreated())->setContentSource($transaction->getContentSource()); $content = null; $content_class = null; $content = null; switch ($transaction->getTransactionType()) { case ConpherenceTransactionType::TYPE_TITLE: $content = $transaction->getTitle(); $transaction_view->addClass('conpherence-edited'); break; case ConpherenceTransactionType::TYPE_FILES: $content = $transaction->getTitle(); break; case ConpherenceTransactionType::TYPE_PARTICIPANTS: $content = $transaction->getTitle(); $transaction_view->addClass('conpherence-edited'); break; case PhabricatorTransactions::TYPE_COMMENT: $comment = $transaction->getComment(); $content = $this->markupEngine->getOutput($comment, PhabricatorApplicationTransactionComment::MARKUP_FIELD_COMMENT); $content_class = 'conpherence-message phabricator-remarkup'; $transaction_view->setImageURI($author->getImageURI())->setActions(array($author->renderLink())); break; } $transaction_view->appendChild(phutil_tag('div', array('class' => $content_class), $content)); return $transaction_view->render(); }
function phabricator_datetime($epoch, $user) { return phabricator_format_local_time($epoch, $user, pht('%s, g:i A', _phabricator_date_format($epoch))); }
private function getDisplayYearAndMonthAndDay($range_start, $range_end, $display) { $viewer = $this->requireViewer(); $epoch = null; if ($this->calendarYear && $this->calendarMonth) { $start_year = $this->calendarYear; $start_month = $this->calendarMonth; $start_day = $this->calendarDay ? $this->calendarDay : 1; } else { if ($range_start) { $epoch = $range_start; } else { if ($range_end) { $epoch = $range_end; } else { $epoch = time(); } } if ($display == 'month') { $day = 1; } else { $day = phabricator_format_local_time($epoch, $viewer, 'd'); } $start_year = phabricator_format_local_time($epoch, $viewer, 'Y'); $start_month = phabricator_format_local_time($epoch, $viewer, 'm'); $start_day = $day; } return array($start_year, $start_month, $start_day); }
private function formatBucketRows($stats, $day_buckets) { $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; $period = $template; foreach ($stats as $bucket => $info) { $epoch = $day_buckets[$bucket]; $week_bucket = $this->buildBucket($epoch, 'YW'); if ($week_bucket != $last_week) { if ($week) { $rows[] = $this->formatBurnRow('Week of ' . phabricator_date($last_week_epoch, $this->user), $week); $rowc[] = 'week'; } $week = $template; $last_week = $week_bucket; $last_week_epoch = $epoch; } $month_bucket = $this->buildBucket($epoch, 'Ym'); if ($month_bucket != $last_month) { if ($month) { $rows[] = $this->formatBurnRow(phabricator_format_local_time($last_month_epoch, $this->user, 'F, Y'), $month); $rowc[] = 'month'; } $month = $template; $last_month = $month_bucket; $last_month_epoch = $epoch; } $rows[] = $this->formatBurnRow(phabricator_date($epoch, $this->user), $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']; } return array($rows, $rowc, $week, $month, $period); }
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 renderBurn() { $request = $this->getRequest(); $user = $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.taskID = t.id JOIN %T p ON p.taskPHID = t.phid AND p.projectPHID = %s', id(new ManiphestTask())->getTableName(), id(new ManiphestTaskProject())->getTableName(), $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, ManiphestTransactionType::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'], '"'); $old_is_open = $oldv === (string) ManiphestTaskStatus::STATUS_OPEN; $new_is_open = $newv === (string) ManiphestTaskStatus::STATUS_OPEN; $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'], $user, '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, $user, 'YW'); if ($week_bucket != $last_week) { if ($week) { $rows[] = $this->formatBurnRow('Week of ' . phabricator_date($last_week_epoch, $user), $week); $rowc[] = 'week'; } $week = $template; $last_week = $week_bucket; $last_week_epoch = $epoch; } $month_bucket = phabricator_format_local_time($epoch, $user, 'Ym'); if ($month_bucket != $last_month) { if ($month) { $rows[] = $this->formatBurnRow(phabricator_format_local_time($last_month_epoch, $user, 'F, Y'), $month); $rowc[] = 'month'; } $month = $template; $last_month = $month_bucket; $last_month_epoch = $epoch; } $rows[] = $this->formatBurnRow(phabricator_date($epoch, $user), $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('Week To Date', $week); $rowc[] = 'week'; } if ($month) { $rows[] = $this->formatBurnRow('Month To Date', $month); $rowc[] = 'month'; } $rows[] = $this->formatBurnRow('All Time', $period); $rowc[] = 'aggregate'; $rows = array_reverse($rows); $rowc = array_reverse($rowc); $table = new AphrontTableView($rows); $table->setRowClasses($rowc); $table->setHeaders(array('Period', 'Opened', 'Closed', 'Change')); $table->setColumnClasses(array('right wide', 'n', 'n', 'n')); if ($handle) { $header = "Task Burn Rate for Project " . $handle->renderLink(); $caption = "<p>NOTE: This table reflects tasks <em>currently</em> 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.</p>"; } else { $header = "Task Burn Rate for All Tasks"; $caption = null; } $panel = new AphrontPanelView(); $panel->setHeader($header); $panel->setCaption($caption); $panel->appendChild($table); $tokens = array(); if ($handle) { $tokens = array($handle->getPHID() => $handle->getFullName()); } $filter = $this->renderReportFilters($tokens, $has_window = false); $id = celerity_generate_unique_node_id(); $chart = phutil_render_tag('div', array('id' => $id, 'style' => 'border: 1px solid #6f6f6f; ' . 'margin: 1em 2em; ' . 'height: 400px; '), ''); list($burn_x, $burn_y) = $this->buildSeries($data); require_celerity_resource('raphael-core'); require_celerity_resource('raphael-g'); require_celerity_resource('raphael-g-line'); Javelin::initBehavior('line-chart', array('hardpoint' => $id, 'x' => array($burn_x), 'y' => array($burn_y), 'xformat' => 'epoch')); return array($filter, $chart, $panel); }
private function renderUserCalendar(PhabricatorUser $user) { $viewer = $this->getRequest()->getUser(); $epochs = CalendarTimeUtil::getCalendarEventEpochs($viewer, 'today', 7); $start_epoch = $epochs['start_epoch']; $end_epoch = $epochs['end_epoch']; $statuses = id(new PhabricatorCalendarEventQuery())->setViewer($viewer)->withInvitedPHIDs(array($user->getPHID()))->withDateRange($start_epoch, $end_epoch)->execute(); $timestamps = CalendarTimeUtil::getCalendarWeekTimestamps($viewer); $today = $timestamps['today']; $epoch_stamps = $timestamps['epoch_stamps']; $events = array(); foreach ($epoch_stamps as $day) { $epoch_start = $day->format('U'); $next_day = clone $day; $next_day->modify('+1 day'); $epoch_end = $next_day->format('U'); foreach ($statuses as $status) { if ($status->getDateTo() < $epoch_start) { continue; } if ($status->getDateFrom() >= $epoch_end) { continue; } $event = new AphrontCalendarEventView(); $event->setEpochRange($status->getDateFrom(), $status->getDateTo()); $status_text = $status->getHumanStatus(); $event->setUserPHID($status->getUserPHID()); $event->setName($status_text); $event->setDescription($status->getDescription()); $event->setEventID($status->getID()); $events[$epoch_start][] = $event; } } $week = array(); foreach ($epoch_stamps as $day) { $epoch = $day->format('U'); $headertext = phabricator_format_local_time($epoch, $user, 'l, M d'); $list = new PHUICalendarListView(); $list->setUser($viewer); $list->showBlankState(true); if (isset($events[$epoch])) { foreach ($events[$epoch] as $event) { $list->addEvent($event); } } $header = phutil_tag('a', array('href' => $this->getRequest()->getRequestURI() . 'calendar/'), $headertext); $calendar = new PHUICalendarWidgetView(); $calendar->setHeader($header); $calendar->setCalendarList($list); $week[] = $calendar; } return phutil_tag_div('profile-calendar', $week); }
protected function renderResultList(array $events, PhabricatorSavedQuery $query, array $handles) { assert_instances_of($events, 'PhabricatorCalendarEvent'); $viewer = $this->requireViewer(); $list = new PHUIObjectItemListView(); foreach ($events as $event) { if ($event->getUserPHID() == $viewer->getPHID()) { $href = $this->getApplicationURI('/event/edit/' . $event->getID() . '/'); } else { $from = $event->getDateFrom(); $month = phabricator_format_local_time($from, $viewer, 'm'); $year = phabricator_format_local_time($from, $viewer, 'Y'); $uri = new PhutilURI($this->getApplicationURI()); $uri->setQueryParams(array('month' => $month, 'year' => $year)); $href = (string) $uri; } $from = phabricator_datetime($event->getDateFrom(), $viewer); $to = phabricator_datetime($event->getDateTo(), $viewer); $creator_handle = $handles[$event->getUserPHID()]; $color = $event->getStatus() == PhabricatorCalendarEvent::STATUS_AWAY ? 'red' : 'yellow'; $item = id(new PHUIObjectItemView())->setHeader($event->getTerseSummary($viewer))->setHref($href)->setBarColor($color)->addByline(pht('Creator: %s', $creator_handle->renderLink()))->addAttribute(pht('From %s to %s', $from, $to))->addAttribute(id(new PhutilUTF8StringTruncator())->setMaximumGlyphs(64)->truncateString($event->getDescription())); $list->addItem($item); } return $list; }
function phabricator_datetime($epoch, $user) { $time_key = PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT; return phabricator_format_local_time($epoch, $user, pht('%s, %s', phutil_date_format($epoch), $user->getPreference($time_key))); }
function phabricator_datetime($epoch, $user) { return phabricator_format_local_time($epoch, $user, _phabricator_date_format($epoch) . ', g:i A'); }
private function getCurrentYear() { return phabricator_format_local_time(time(), $this->getUser(), 'Y'); }
private function formatTime($epoch, $fmt) { return phabricator_format_local_time($epoch, $this->getViewer(), $fmt); }
public static function renderTransactions(PhabricatorUser $user, ConpherenceThread $conpherence, $marker_type = 'older') { $transactions = $conpherence->getTransactions(); $oldest_transaction_id = 0; $newest_transaction_id = 0; $too_many = ConpherenceThreadQuery::TRANSACTION_LIMIT + 1; if (count($transactions) == $too_many) { if ($marker_type == 'olderandnewer') { $last_transaction = end($transactions); $first_transaction = reset($transactions); unset($transactions[$last_transaction->getID()]); unset($transactions[$first_transaction->getID()]); $oldest_transaction_id = $last_transaction->getID(); $newest_transaction_id = $first_transaction->getID(); } else { if ($marker_type == 'newer') { $first_transaction = reset($transactions); unset($transactions[$first_transaction->getID()]); $newest_transaction_id = $first_transaction->getID(); } else { if ($marker_type == 'older') { $last_transaction = end($transactions); unset($transactions[$last_transaction->getID()]); $oldest_transaction = end($transactions); $oldest_transaction_id = $oldest_transaction->getID(); } } } // we need **at least** the newer marker in this mode even if // we didn't get a full set of transactions } else { if ($marker_type == 'olderandnewer') { $first_transaction = reset($transactions); unset($transactions[$first_transaction->getID()]); $newest_transaction_id = $first_transaction->getID(); } } $transactions = array_reverse($transactions); $handles = $conpherence->getHandles(); $rendered_transactions = array(); $engine = id(new PhabricatorMarkupEngine())->setViewer($user)->setContextObject($conpherence); foreach ($transactions as $key => $transaction) { if ($transaction->shouldHide()) { unset($transactions[$key]); continue; } if ($transaction->getComment()) { $engine->addObject($transaction->getComment(), PhabricatorApplicationTransactionComment::MARKUP_FIELD_COMMENT); } } $engine->process(); // we're going to insert a dummy date marker transaction for breaks // between days. some setup required! $previous_transaction = null; $date_marker_transaction = id(new ConpherenceTransaction())->setTransactionType(ConpherenceTransaction::TYPE_DATE_MARKER)->makeEphemeral(); $date_marker_transaction_view = id(new ConpherenceTransactionView())->setUser($user)->setConpherenceTransaction($date_marker_transaction)->setConpherenceThread($conpherence)->setHandles($handles)->setMarkupEngine($engine); $transaction_view_template = id(new ConpherenceTransactionView())->setUser($user)->setConpherenceThread($conpherence)->setHandles($handles)->setMarkupEngine($engine); foreach ($transactions as $transaction) { $collapsed = false; if ($previous_transaction) { $previous_day = phabricator_format_local_time($previous_transaction->getDateCreated(), $user, 'Ymd'); $current_day = phabricator_format_local_time($transaction->getDateCreated(), $user, 'Ymd'); // See if same user / time $previous_author = $previous_transaction->getAuthorPHID(); $current_author = $transaction->getAuthorPHID(); $previous_time = $previous_transaction->getDateCreated(); $current_time = $transaction->getDateCreated(); $previous_type = $previous_transaction->getTransactionType(); $current_type = $transaction->getTransactionType(); if ($previous_author == $current_author && $previous_type == $current_type) { // Group messages within the last x seconds if ($current_time - $previous_time < 120) { $collapsed = true; } } // date marker transaction time! if ($previous_day != $current_day) { $date_marker_transaction->setDateCreated($transaction->getDateCreated()); $date_marker_transaction->setID($previous_transaction->getID()); $rendered_transactions[] = $date_marker_transaction_view->render(); } } $transaction_view = id(clone $transaction_view_template)->setConpherenceTransaction($transaction); if ($collapsed) { $transaction_view->addClass('conpherence-transaction-collapsed'); } $rendered_transactions[] = $transaction_view->render(); $previous_transaction = $transaction; } $latest_transaction_id = $transaction->getID(); return array('transactions' => $rendered_transactions, 'latest_transaction' => $transaction, 'latest_transaction_id' => $latest_transaction_id, 'oldest_transaction_id' => $oldest_transaction_id, 'newest_transaction_id' => $newest_transaction_id); }
function phabricator_datetime($epoch, $user) { return phabricator_format_local_time($epoch, $user, pht('%s, %s', _phutil_date_format($epoch), _phabricator_time_format($user))); }
public function __construct($project, $viewer) { $this->project = $project; $this->viewer = $viewer; // We need the custom fields so we can pull out the start and end date $field_list = PhabricatorCustomField::getObjectFields($this->project, PhabricatorCustomField::ROLE_EDIT); $field_list->setViewer($viewer); $field_list->readFieldsFromStorage($this->project); $aux_fields = $field_list->getFields(); $start = idx($aux_fields, 'isdc:sprint:startdate')->getProxy()->getFieldValue(); $end = idx($aux_fields, 'isdc:sprint:enddate')->getProxy()->getFieldValue(); if (!$start or !$end) { throw new BurndownException("This project is not set up for Burndowns, " . "make sure it has 'Sprint' in the name, and then edit it to add the " . "sprint start and end date."); } // Load the data for the chart. This approach tries to be simple, but loads // and processes large amounts of unnecessary data, so it is not especially // fast. Some performance improvements can be made at the cost of fragility // by using raw SQL; real improvements can be made once Facts comes online. // First, load *every task* in the project. We have to do something like // this because there's no straightforward way to determine which tasks // have activity in the project period. $tasks = id(new ManiphestTaskQuery())->setViewer($viewer)->withEdgeLogicPHIDs(PhabricatorProjectObjectHasProjectEdgeType::EDGECONST, PhabricatorQueryConstraint::OPERATOR_OR, array($this->project->getPHID()))->needProjectPHIDs(true)->execute(); // Now load *every transaction* for those tasks. This loads all the // comments, etc., for every one of the tasks. Again, not very fast, but // we largely do not have ways to select this data more narrowly yet. if (!$tasks) { throw new BurndownException("This project has no tasks."); } $task_phids = mpull($tasks, 'getPHID'); $xactions = id(new ManiphestTransactionQuery())->setViewer($viewer)->withObjectPHIDs($task_phids)->execute(); // Examine all the transactions and extract "events" out of them. These are // times when a task was opened or closed. Make some effort to also track // "scope" events (when a task was added or removed from a project). $scope_phids = array($this->project->getPHID()); $this->events = $this->extractEvents($xactions, $scope_phids); $this->xactions = mpull($xactions, null, 'getPHID'); $this->tasks = mpull($tasks, null, 'getPHID'); // Build an array of dates between start and end $period = new DatePeriod(id(new DateTime("@" . $start))->setTime(0, 0), new DateInterval('P1D'), id(new DateTime("@" . $end))->modify('+1 day')->setTime(0, 0)); $this->dates = array('before' => new BurndownDataDate('Start of Sprint')); foreach ($period as $day) { $this->dates[$day->format('D M j')] = new BurndownDataDate($day->format('D M j')); } $this->dates['after'] = new BurndownDataDate('After end of Sprint'); // Build arrays to store current point and closed status of tasks as we // progress through time, so that these changes reflect on the graph $this->task_points = array(); $this->task_statuses = array(); foreach ($this->tasks as $task) { $this->task_points[$task->getPHID()] = 0; $this->task_statuses[$task->getPHID()] = null; $this->task_in_sprint[$task->getPHID()] = 0; } // This is fairly cludgy. We want anything created before the midnight // following the "start date" to show under "start of sprint", however we // want this to respect the *viewers time zone*. So we format the start date // according to the users settings convert it to date time, set it to // midnight of the next day and then convert it back to unix time stamp. // We then do the same gross process for the end date. $start_date_midnight = id(new DateTime("@" . phabricator_format_local_time($start, $viewer, 'U')))->modify('+1 day')->setTime(0, 0)->getTimestamp(); $end_date_midnight = id(new DateTime("@" . phabricator_format_local_time($end, $viewer, 'U')))->modify('+1 day')->setTime(0, 0)->getTimestamp(); // Now loop through the events and build the data for each day foreach ($this->events as $event) { $xaction = $this->xactions[$event['transactionPHID']]; $xaction_date = $xaction->getDateCreated(); $task_phid = $xaction->getObjectPHID(); $task = $this->tasks[$task_phid]; // Determine which date to attach this data to if ($xaction_date < $start_date_midnight) { $date = 'before'; } else { if ($xaction_date > $end_date_midnight) { $date = 'after'; } else { //$date = id(new DateTime("@".$xaction_date))->format('D M j'); $date = phabricator_format_local_time($xaction_date, $viewer, 'D M j'); } } switch ($event['type']) { case "create": // Will be accounted for by "task-add" when the project is added // Bet we still include it so it shows on the Events list break; case "task-add": // A task was added to the sprint $this->addTaskToSprint($date, $task_phid); break; case "task-remove": // A task was removed from the sprint $this->removeTaskFromSprint($date, $task_phid); break; case "close": // A task was closed, mark it as done $this->closeTask($date, $task_phid); break; case "reopen": // A task was reopened, subtract from done $this->reopenTask($date, $task_phid); break; case "points": // Points were changed $this->changePoints($date, $task_phid, $xaction); break; } } // Now that we have the data for each day, we need to loop over and sum // up the relevant columns. Start by making a zeroed "previous" object $previous = (object) array('tasks_total' => 0, 'points_total' => 0, 'tasks_remaining' => 0, 'points_remaining' => 0); foreach ($this->dates as $current) { $current->tasks_total = $previous->tasks_total + $current->tasks_added_today; $current->points_total = $previous->points_total + $current->points_added_today; $current->tasks_remaining = $previous->tasks_remaining + $current->tasks_added_today - $current->tasks_closed_today; $current->points_remaining = $previous->points_remaining + $current->points_added_today - $current->points_closed_today; $previous = $current; } $this->computeIdealPoints(); }
private function renderCalendarWidgetPaneContent() { $user = $this->getRequest()->getUser(); $conpherence = $this->getConpherence(); $participants = $conpherence->getParticipants(); $widget_data = $conpherence->getWidgetData(); // TODO: This panel is built around an outdated notion of events and isn't // invitee-aware. $statuses = $widget_data['events']; $handles = $conpherence->getHandles(); $content = array(); $layout = id(new AphrontMultiColumnView())->setFluidLayout(true); $timestamps = CalendarTimeUtil::getCalendarWidgetTimestamps($user); $today = $timestamps['today']; $epoch_stamps = $timestamps['epoch_stamps']; $one_day = 24 * 60 * 60; $is_today = false; $calendar_columns = 0; $list_days = 0; foreach ($epoch_stamps as $day) { // build a header for the new day if ($day->format('Ymd') == $today->format('Ymd')) { $active_class = 'today'; $is_today = true; } else { $active_class = ''; $is_today = false; } $should_draw_list = $list_days < 7; $list_days++; if ($should_draw_list) { $content[] = phutil_tag('div', array('class' => 'day-header ' . $active_class), array(phutil_tag('div', array('class' => 'day-name'), $day->format('l')), phutil_tag('div', array('class' => 'day-date'), $day->format('m/d/y')))); } $week_day_number = $day->format('w'); $epoch_start = $day->format('U'); $next_day = clone $day; $next_day->modify('+1 day'); $epoch_end = $next_day->format('U'); $first_status_of_the_day = true; $statuses_of_the_day = array(); // keep looking through statuses where we last left off foreach ($statuses as $status) { if ($status->getDateFrom() >= $epoch_end) { // This list is sorted, so we can stop looking. break; } if ($status->getDateFrom() < $epoch_end && $status->getDateTo() > $epoch_start) { $statuses_of_the_day[$status->getUserPHID()] = $status; if ($should_draw_list) { $top_border = ''; if (!$first_status_of_the_day) { $top_border = ' top-border'; } $timespan = $status->getDateTo() - $status->getDateFrom(); if ($timespan > $one_day) { $time_str = 'm/d'; } else { $time_str = 'h:i A'; } $epoch_range = phabricator_format_local_time($status->getDateFrom(), $user, $time_str) . ' - ' . phabricator_format_local_time($status->getDateTo(), $user, $time_str); if (isset($handles[$status->getUserPHID()])) { $secondary_info = pht('%s, %s', $handles[$status->getUserPHID()]->getName(), $epoch_range); } else { $secondary_info = $epoch_range; } $content[] = phutil_tag('div', array('class' => 'user-status ' . $top_border), array(phutil_tag('div', array('class' => 'icon'), ''), phutil_tag('div', array('class' => 'description'), array($status->getName(), phutil_tag('div', array('class' => 'participant'), $secondary_info))))); } $first_status_of_the_day = false; } } // we didn't get a status on this day so add a spacer if ($first_status_of_the_day && $should_draw_list) { $content[] = phutil_tag('div', array('class' => 'no-events pm'), pht('No Events Scheduled.')); } if ($is_today || $calendar_columns && $calendar_columns < 3) { $active_class = ''; if ($is_today) { $active_class = '-active'; } $inner_layout = array(); foreach ($participants as $phid => $participant) { $status = idx($statuses_of_the_day, $phid, false); if ($status) { $inner_layout[] = phutil_tag('div', array(), ''); } else { $inner_layout[] = phutil_tag('div', array('class' => 'present'), ''); } } $layout->addColumn(phutil_tag('div', array('class' => 'day-column' . $active_class), array(phutil_tag('div', array('class' => 'day-name'), $day->format('D')), phutil_tag('div', array('class' => 'day-number'), $day->format('j')), $inner_layout))); $calendar_columns++; } } return array($layout, $content); }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $start_time = id(new AphrontFormDateControl())->setUser($user)->setName('start')->setLabel(pht('Start'))->setInitialTime(AphrontFormDateControl::TIME_START_OF_DAY); $end_time = id(new AphrontFormDateControl())->setUser($user)->setName('end')->setLabel(pht('End'))->setInitialTime(AphrontFormDateControl::TIME_END_OF_DAY); if ($this->isCreate()) { $status = new PhabricatorCalendarEvent(); $end_value = $end_time->readValueFromRequest($request); $start_value = $start_time->readValueFromRequest($request); $submit_label = pht('Create'); $filter = 'status/create/'; $page_title = pht('Create Event'); $redirect = 'created'; } else { $status = id(new PhabricatorCalendarEventQuery())->setViewer($user)->withIDs(array($this->id))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne(); if (!$status) { return new Aphront404Response(); } $end_time->setValue($status->getDateTo()); $start_time->setValue($status->getDateFrom()); $submit_label = pht('Update'); $filter = 'event/edit/' . $status->getID() . '/'; $page_title = pht('Update Event'); $redirect = 'updated'; } $errors = array(); if ($request->isFormPost()) { $type = $request->getInt('status'); $start_value = $start_time->readValueFromRequest($request); $end_value = $end_time->readValueFromRequest($request); $description = $request->getStr('description'); try { $status->setUserPHID($user->getPHID())->setStatus($type)->setDateFrom($start_value)->setDateTo($end_value)->setDescription($description)->save(); } catch (PhabricatorCalendarEventInvalidEpochException $e) { $errors[] = pht('Start must be before end.'); } if (!$errors) { $uri = new PhutilURI($this->getApplicationURI()); $uri->setQueryParams(array('month' => phabricator_format_local_time($status->getDateFrom(), $user, 'm'), 'year' => phabricator_format_local_time($status->getDateFrom(), $user, 'Y'), $redirect => true)); if ($request->isAjax()) { $response = id(new AphrontAjaxResponse())->setContent(array('redirect_uri' => $uri)); } else { $response = id(new AphrontRedirectResponse())->setURI($uri); } return $response; } } $error_view = null; if ($errors) { $error_view = id(new AphrontErrorView())->setTitle(pht('Status can not be set!'))->setErrors($errors); } $status_select = id(new AphrontFormSelectControl())->setLabel(pht('Status'))->setName('status')->setValue($status->getStatus())->setOptions($status->getStatusOptions()); $description = id(new AphrontFormTextAreaControl())->setLabel(pht('Description'))->setName('description')->setValue($status->getDescription()); if ($request->isAjax()) { $dialog = id(new AphrontDialogView())->setUser($user)->setTitle($page_title)->setWidth(AphrontDialogView::WIDTH_FORM); if ($this->isCreate()) { $dialog->setSubmitURI($this->getApplicationURI('event/create/')); } else { $dialog->setSubmitURI($this->getApplicationURI('event/edit/' . $status->getID() . '/')); } $form = new PHUIFormLayoutView(); if ($error_view) { $form->appendChild($error_view); } } else { $form = id(new AphrontFormView())->setUser($user); } $form->appendChild($status_select)->appendChild($start_time)->appendChild($end_time)->appendChild($description); if ($request->isAjax()) { $dialog->addSubmitButton($submit_label); $submit = $dialog; } else { $submit = id(new AphrontFormSubmitControl())->setValue($submit_label); } if ($this->isCreate()) { $submit->addCancelButton($this->getApplicationURI()); } else { $submit->addCancelButton($this->getApplicationURI('event/view/' . $status->getID() . '/')); } if ($request->isAjax()) { $dialog->appendChild($form); return id(new AphrontDialogResponse())->setDialog($dialog); } $form->appendChild($submit); $form_box = id(new PHUIObjectBoxView())->setHeaderText($page_title)->setFormErrors($errors)->setForm($form); $nav = $this->buildSideNavView($status); $nav->selectFilter($filter); $crumbs = $this->buildApplicationCrumbs()->addTextCrumb($page_title); $nav->appendChild(array($crumbs, $form_box)); return $this->buildApplicationPage($nav, array('title' => $page_title)); }
private function formatTime($epoch, $format) { return phabricator_format_local_time($epoch, $this->viewer, $format); }
function phabricator_datetime($epoch, $user) { $time_key = PhabricatorTimeFormatSetting::SETTINGKEY; return phabricator_format_local_time($epoch, $user, pht('%s, %s', phutil_date_format($epoch), $user->getUserSetting($time_key))); }