diff --git a/src/applications/phrequent/controller/PhrequentListController.php b/src/applications/phrequent/controller/PhrequentListController.php index bb1ea82129..6cfd8755dc 100644 --- a/src/applications/phrequent/controller/PhrequentListController.php +++ b/src/applications/phrequent/controller/PhrequentListController.php @@ -1,146 +1,205 @@ getRequest(); $user = $request->getUser(); $nav = $this->buildNav('usertime'); + $form = id(new AphrontFormView()) + ->setUser($user) + ->setNoShading(true); + + $form->appendChild( + id(new AphrontFormToggleButtonsControl()) + ->setName('o') + ->setLabel(pht('Sort Order')) + ->setBaseURI($request->getRequestURI(), 'o') + ->setValue($request->getStr('o', 's')) + ->setButtons( + array( + 's' => pht('Started'), + 'e' => pht('Ended'), + 'd' => pht('Duration'), + ))); + + $form->appendChild( + id(new AphrontFormToggleButtonsControl()) + ->setName('e') + ->setLabel(pht('Ended')) + ->setBaseURI($request->getRequestURI(), 'e') + ->setValue($request->getStr('e', 'a')) + ->setButtons( + array( + 'y' => pht('Yes'), + 'n' => pht('No'), + 'a' => pht('All'), + ))); + + $filter = new AphrontListFilterView(); + $filter->appendChild($form); + $query = new PhrequentUserTimeQuery(); - $query->setOrder(PhrequentUserTimeQuery::ORDER_ENDED); + + switch ($request->getStr('o', 's')) { + case 's': + $order = PhrequentUserTimeQuery::ORDER_STARTED; + break; + case 'e': + $order = PhrequentUserTimeQuery::ORDER_ENDED; + break; + case 'd': + $order = PhrequentUserTimeQuery::ORDER_DURATION; + break; + default: + throw new Exception("Unknown order!"); + } + $query->setOrder($order); + + switch ($request->getStr('e', 'a')) { + case 'a': + $ended = PhrequentUserTimeQuery::ENDED_ALL; + break; + case 'y': + $ended = PhrequentUserTimeQuery::ENDED_YES; + break; + case 'n': + $ended = PhrequentUserTimeQuery::ENDED_NO; + break; + default: + throw new Exception("Unknown ended!"); + } + $query->setEnded($ended); $pager = new AphrontPagerView(); $pager->setPageSize(500); $pager->setOffset($request->getInt('offset')); $pager->setURI($request->getRequestURI(), 'offset'); $logs = $query->executeWithOffsetPager($pager); $title = pht('Time Tracked'); - $header = id(new PhabricatorHeaderView()) - ->setHeader($title); - $table = $this->buildTableView($logs); $table->appendChild($pager); $nav->appendChild( array( - $header, + $filter, $table, $pager, )); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addCrumb( id(new PhabricatorCrumbView()) ->setName($title) ->setHref($this->getApplicationURI('/'))); $nav->setCrumbs($crumbs); return $this->buildApplicationPage( $nav, array( 'title' => $title, 'device' => true, )); } protected function buildTableView(array $usertimes) { assert_instances_of($usertimes, 'PhrequentUserTime'); $user = $this->getRequest()->getUser(); $phids = array(); foreach ($usertimes as $usertime) { $phids[] = $usertime->getUserPHID(); $phids[] = $usertime->getObjectPHID(); } $handles = $this->loadViewerHandles($phids); $rows = array(); foreach ($usertimes as $usertime) { if ($usertime->getDateEnded() !== null) { $time_spent = $usertime->getDateEnded() - $usertime->getDateStarted(); $time_ended = phabricator_datetime($usertime->getDateEnded(), $user); } else { $time_spent = time() - $usertime->getDateStarted(); $time_ended = phutil_tag( 'em', array(), pht('Ongoing')); } $usertime_user = $handles[$usertime->getUserPHID()]; $usertime_object = null; $object = null; if ($usertime->getObjectPHID() !== null) { $usertime_object = $handles[$usertime->getObjectPHID()]; $object = phutil_tag( 'a', array( 'href' => $usertime_object->getURI() ), $usertime_object->getFullName()); } else { $object = phutil_tag( 'em', array(), pht('None')); } $rows[] = array( $object, phutil_tag( 'a', array( 'href' => $usertime_user->getURI() ), $usertime_user->getFullName()), phabricator_datetime($usertime->getDateStarted(), $user), $time_ended, $time_spent == 0 ? 'none' : phabricator_format_relative_time_detailed($time_spent), $usertime->getNote() ); } $table = new AphrontTableView($rows); $table->setDeviceReadyTable(true); $table->setHeaders( array( 'Object', 'User', 'Started', 'Ended', 'Duration', 'Note' )); $table->setShortHeaders( array( 'O', 'U', 'S', 'E', 'D', 'Note', '', )); $table->setColumnClasses( array( '', '', '', '', '', 'wide' )); return $table; } } diff --git a/src/applications/phrequent/query/PhrequentUserTimeQuery.php b/src/applications/phrequent/query/PhrequentUserTimeQuery.php index c659b9556b..4ab0351309 100644 --- a/src/applications/phrequent/query/PhrequentUserTimeQuery.php +++ b/src/applications/phrequent/query/PhrequentUserTimeQuery.php @@ -1,193 +1,220 @@ userPHIDs = $user_phids; return $this; } public function setObjects($object_phids) { $this->objectPHIDs = $object_phids; return $this; } public function setOrder($order) { $this->order = $order; return $this; } + public function setEnded($ended) { + $this->ended = $ended; + return $this; + } + public function execute() { $usertime_dao = new PhrequentUserTime(); $conn = $usertime_dao->establishConnection('r'); $data = queryfx_all( $conn, 'SELECT usertime.* FROM %T usertime %Q %Q %Q', $usertime_dao->getTableName(), $this->buildWhereClause($conn), $this->buildOrderClause($conn), $this->buildLimitClause($conn)); return $usertime_dao->loadAllFromArray($data); } private function buildWhereClause(AphrontDatabaseConnection $conn) { $where = array(); if ($this->userPHIDs) { $where[] = qsprintf( $conn, 'userPHID IN (%Ls)', $this->userPHIDs); } if ($this->objectPHIDs) { $where[] = qsprintf( $conn, 'objectPHID IN (%Ls)', $this->objectPHIDs); } + switch ($this->ended) { + case self::ENDED_ALL: + break; + case self::ENDED_YES: + $where[] = qsprintf( + $conn, + 'dateEnded IS NOT NULL'); + break; + case self::ENDED_NO: + $where[] = qsprintf( + $conn, + 'dateEnded IS NULL'); + break; + default: + throw new Exception("Unknown ended '{$this->ended}'!"); + } + return $this->formatWhereClause($where); } private function buildOrderClause(AphrontDatabaseConnection $conn) { switch ($this->order) { case self::ORDER_ID: return 'ORDER BY id ASC'; case self::ORDER_STARTED: return 'ORDER BY dateStarted DESC'; case self::ORDER_ENDED: return 'ORDER BY dateEnded IS NULL, dateEnded DESC, dateStarted DESC'; case self::ORDER_DURATION: - return 'ORDER BY (COALESCE(dateEnded, UNIX_TIMESTAMP() - dateStarted) '. + return 'ORDER BY COALESCE(dateEnded, UNIX_TIMESTAMP()) - dateStarted '. 'DESC'; default: throw new Exception("Unknown order '{$this->order}'!"); } } /* -( Helper Functions ) --------------------------------------------------- */ public static function getUserTotalObjectsTracked( PhabricatorUser $user) { $usertime_dao = new PhrequentUserTime(); $conn = $usertime_dao->establishConnection('r'); $count = queryfx_one( $conn, 'SELECT COUNT(usertime.id) N FROM %T usertime '. 'WHERE usertime.userPHID = %s '. 'AND usertime.dateEnded IS NULL', $usertime_dao->getTableName(), $user->getPHID()); return $count['N']; } public static function isUserTrackingObject( PhabricatorUser $user, $phid) { $usertime_dao = new PhrequentUserTime(); $conn = $usertime_dao->establishConnection('r'); $count = queryfx_one( $conn, 'SELECT COUNT(usertime.id) N FROM %T usertime '. 'WHERE usertime.userPHID = %s '. 'AND usertime.objectPHID = %s '. 'AND usertime.dateEnded IS NULL', $usertime_dao->getTableName(), $user->getPHID(), $phid); return $count['N'] > 0; } public static function loadUserStack(PhabricatorUser $user) { if (!$user->isLoggedIn()) { return array(); } return id(new PhrequentUserTime())->loadAllWhere( 'userPHID = %s AND dateEnded IS NULL ORDER BY dateStarted DESC, id DESC', $user->getPHID()); } public static function getTotalTimeSpentOnObject($phid) { $usertime_dao = new PhrequentUserTime(); $conn = $usertime_dao->establishConnection('r'); // First calculate all the time spent where the // usertime blocks have ended. $sum_ended = queryfx_one( $conn, 'SELECT SUM(usertime.dateEnded - usertime.dateStarted) N '. 'FROM %T usertime '. 'WHERE usertime.objectPHID = %s '. 'AND usertime.dateEnded IS NOT NULL', $usertime_dao->getTableName(), $phid); // Now calculate the time spent where the usertime // blocks have not yet ended. $sum_not_ended = queryfx_one( $conn, 'SELECT SUM(UNIX_TIMESTAMP() - usertime.dateStarted) N '. 'FROM %T usertime '. 'WHERE usertime.objectPHID = %s '. 'AND usertime.dateEnded IS NULL', $usertime_dao->getTableName(), $phid); return $sum_ended['N'] + $sum_not_ended['N']; } public static function getUserTimeSpentOnObject( PhabricatorUser $user, $phid) { $usertime_dao = new PhrequentUserTime(); $conn = $usertime_dao->establishConnection('r'); // First calculate all the time spent where the // usertime blocks have ended. $sum_ended = queryfx_one( $conn, 'SELECT SUM(usertime.dateEnded - usertime.dateStarted) N '. 'FROM %T usertime '. 'WHERE usertime.userPHID = %s '. 'AND usertime.objectPHID = %s '. 'AND usertime.dateEnded IS NOT NULL', $usertime_dao->getTableName(), $user->getPHID(), $phid); // Now calculate the time spent where the usertime // blocks have not yet ended. $sum_not_ended = queryfx_one( $conn, 'SELECT SUM(UNIX_TIMESTAMP() - usertime.dateStarted) N '. 'FROM %T usertime '. 'WHERE usertime.userPHID = %s '. 'AND usertime.objectPHID = %s '. 'AND usertime.dateEnded IS NULL', $usertime_dao->getTableName(), $user->getPHID(), $phid); return $sum_ended['N'] + $sum_not_ended['N']; } }