Page MenuHomePhabricator

D10162.diff
No OneTemporary

D10162.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -2533,6 +2533,10 @@
'PhrequentConduitAPIMethod' => 'applications/phrequent/conduit/PhrequentConduitAPIMethod.php',
'PhrequentController' => 'applications/phrequent/controller/PhrequentController.php',
'PhrequentDAO' => 'applications/phrequent/storage/PhrequentDAO.php',
+ 'PhrequentEditController' => 'applications/phrequent/controller/PhrequentEditController.php',
+ 'PhrequentExcelDefaultFormat' => 'applications/phrequent/export/PhrequentExcelDefaultFormat.php',
+ 'PhrequentExcelFormat' => 'applications/phrequent/export/PhrequentExcelFormat.php',
+ 'PhrequentExportController' => 'applications/phrequent/controller/PhrequentExportController.php',
'PhrequentListController' => 'applications/phrequent/controller/PhrequentListController.php',
'PhrequentPopConduitAPIMethod' => 'applications/phrequent/conduit/PhrequentPopConduitAPIMethod.php',
'PhrequentPushConduitAPIMethod' => 'applications/phrequent/conduit/PhrequentPushConduitAPIMethod.php',
@@ -5448,6 +5452,9 @@
'PhrequentConduitAPIMethod' => 'ConduitAPIMethod',
'PhrequentController' => 'PhabricatorController',
'PhrequentDAO' => 'PhabricatorLiskDAO',
+ 'PhrequentEditController' => 'PhrequentController',
+ 'PhrequentExcelDefaultFormat' => 'PhrequentExcelFormat',
+ 'PhrequentExportController' => 'PhrequentController',
'PhrequentListController' => 'PhrequentController',
'PhrequentPopConduitAPIMethod' => 'PhrequentConduitAPIMethod',
'PhrequentPushConduitAPIMethod' => 'PhrequentConduitAPIMethod',
diff --git a/src/applications/phrequent/application/PhabricatorPhrequentApplication.php b/src/applications/phrequent/application/PhabricatorPhrequentApplication.php
--- a/src/applications/phrequent/application/PhabricatorPhrequentApplication.php
+++ b/src/applications/phrequent/application/PhabricatorPhrequentApplication.php
@@ -41,7 +41,10 @@
'/phrequent/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'PhrequentListController',
'track/(?P<verb>[a-z]+)/(?P<phid>[^/]+)/'
- => 'PhrequentTrackController'
+ => 'PhrequentTrackController',
+ 'create/' => 'PhrequentEditController',
+ 'edit/(?<id>[0-9]+)/' => 'PhrequentEditController',
+ 'export/(?<key>[^/]+)/' => 'PhrequentExportController'
),
);
}
diff --git a/src/applications/phrequent/controller/PhrequentController.php b/src/applications/phrequent/controller/PhrequentController.php
--- a/src/applications/phrequent/controller/PhrequentController.php
+++ b/src/applications/phrequent/controller/PhrequentController.php
@@ -16,4 +16,16 @@
return $nav;
}
+
+ protected function buildApplicationCrumbs() {
+ $crumbs = parent::buildApplicationCrumbs();
+
+ $crumbs->addAction(
+ id(new PHUIListItemView())
+ ->setName(pht('Create Tracked Time'))
+ ->setHref($this->getApplicationURI('create/'))
+ ->setIcon('create'));
+
+ return $crumbs;
+ }
}
diff --git a/src/applications/phrequent/controller/PhrequentEditController.php b/src/applications/phrequent/controller/PhrequentEditController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phrequent/controller/PhrequentEditController.php
@@ -0,0 +1,176 @@
+<?php
+
+final class PhrequentEditController extends PhrequentController {
+
+ private $id;
+
+ public function willProcessRequest(array $data) {
+ $this->id = idx($data, 'id');
+ }
+
+
+ public function processRequest() {
+ $request = $this->getRequest();
+ $user = $request->getUser();
+ $is_create = !$this->id;
+
+ if ($is_create) {
+ $usertime = id(new PhrequentUserTime())
+ ->setUserPHID($user->getPHID());
+ } else {
+ $usertime = id(new PhrequentUserTimeQuery())
+ ->setViewer($user)
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->withIDs(array($this->id))
+ ->executeOne();
+ if (!$usertime) {
+ return new Aphront404Response();
+ }
+ }
+
+ $phids = array(
+ $usertime->getUserPHID(),
+ $usertime->getObjectPHID());
+
+ $handles = $this->loadViewerHandles($phids);
+
+ $user_control = id(new AphrontFormTokenizerControl())
+ ->setLabel(pht('User'))
+ ->setName('user')
+ ->setUser($user)
+ ->setDatasource(new PhabricatorPeopleDatasource())
+ ->setLimit(1)
+ ->setDisableBehavior(true);
+
+ $object_control = id(new AphrontFormTokenizerControl())
+ ->setLabel(pht('Object'))
+ ->setName('object')
+ ->setUser($user)
+ ->setDatasource(new PhabricatorSearchDatasource())
+ ->setLimit(1);
+
+ $start_control = id(new AphrontFormDateControl())
+ ->setLabel(pht('Start'))
+ ->setName('start')
+ ->setUser($user)
+ ->setInitialTime(AphrontFormDateControl::TIME_START_OF_DAY);
+
+ $end_control = id(new AphrontFormDateControl())
+ ->setLabel(pht('End'))
+ ->setName('end')
+ ->setUser($user)
+ ->setInitialTime(AphrontFormDateControl::TIME_END_OF_DAY);
+
+ $text = null;
+ $errors = array();
+ $error_view = null;
+
+ if ($is_create) {
+ $page_title = pht('New Tracked Time');
+ } else {
+ $page_title = pht('Edit Tracked Time');
+ }
+
+ if ($request->isFormPost()) {
+ $object_value = $request->getArr('object');
+ $user_value = $request->getArr('user');
+ $object_phid = reset($object_value);
+ $user_phid = reset($user_value);
+ $start_value = $start_control->readValueFromRequest($request);
+ $end_value = $end_control->readValueFromRequest($request);
+
+ if (!strlen($object_phid)) {
+ $object_control->setError(pht('Required'));
+ $errors[] = pht('Object is required.');
+ }
+
+ if ($start_value >= $end_value) {
+ $end_control->setError(pht('Undersized'));
+ $errors[] = pht('End must be greater than start.');
+ }
+
+ if (!$errors) {
+ $usertime
+ ->setUserPHID($user_phid)
+ ->setObjectPHID($object_phid)
+ ->setDateStarted($start_value)
+ ->setDateEnded($end_value)
+ ->save();
+
+ $uri = new PhutilURI($this->getApplicationURI());
+
+ if ($request->isAjax()) {
+ $response = id(new AphrontAjaxResponse())
+ ->setContent(array('redirect_uri' => $uri));
+ } else {
+ $response = id(new AphrontRedirectResponse())
+ ->setURI($uri);
+ }
+
+ return $response;
+ }
+ }
+
+ $form = new AphrontFormView();
+
+ if ($error_view) {
+ $form->appendChild($error_view);
+ }
+
+ $form
+ ->setUser($user);
+
+ if (!$is_create) {
+ $user_control->setValue(array($handles[$usertime->getUserPHID()]));
+ $object_control->setValue(array($handles[$usertime->getObjectPHID()]));
+ $start_control->setValue($usertime->getDateStarted());
+ $end_control->setValue($usertime->getDateEnded());
+ } else {
+ $user_control->setValue(array($handles[$usertime->getUserPHID()]));
+ }
+
+ $form
+ ->appendChild($user_control)
+ ->appendChild($object_control)
+ ->appendChild($start_control)
+ ->appendChild($end_control);
+
+ $submit = new AphrontFormSubmitControl();
+ $submit->addCancelButton($this->getApplicationURI());
+
+ if (!$is_create) {
+ $submit->setValue(pht('Save Tracked Time'));
+ $title = pht('Edit Tracked Time');
+ $short = pht('Edit');
+ } else {
+ $submit->setValue(pht('Create Tracked Time'));
+ $title = pht('Create New Tracked Time');
+ $short = pht('Create');
+ }
+
+ $form->appendChild($submit);
+
+ $form_box = id(new PHUIObjectBoxView())
+ ->setHeaderText($title)
+ ->setFormErrors($errors)
+ ->setForm($form);
+
+ $crumbs = $this->buildApplicationCrumbs($this->buildSideNavView());
+ $crumbs->addTextCrumb($page_title);
+
+ return $this->buildApplicationPage(
+ array(
+ $crumbs,
+ $form_box,
+ ),
+ array(
+ 'title' => $title,
+ 'device' => true,
+ ));
+ }
+
+}
diff --git a/src/applications/phrequent/controller/PhrequentExportController.php b/src/applications/phrequent/controller/PhrequentExportController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phrequent/controller/PhrequentExportController.php
@@ -0,0 +1,178 @@
+<?php
+
+final class PhrequentExportController extends PhrequentController {
+ private $key;
+
+ public function willProcessRequest(array $data) {
+ $this->key = $data['key'];
+ return $this;
+ }
+
+ /**
+ * @phutil-external-symbol class PHPExcel
+ * @phutil-external-symbol class PHPExcel_IOFactory
+ * @phutil-external-symbol class PHPExcel_Style_NumberFormat
+ * @phutil-external-symbol class PHPExcel_Cell_DataType
+ */
+ public function processRequest() {
+ $request = $this->getRequest();
+ $user = $request->getUser();
+
+ $ok = @include_once 'PHPExcel.php';
+ if (!$ok) {
+ $dialog = new AphrontDialogView();
+ $dialog->setUser($user);
+
+ $inst1 = pht(
+ 'This system does not have PHPExcel installed. This software '.
+ 'component is required to export tasks to Excel. Have your system '.
+ 'administrator install it from:');
+
+ $inst2 = pht(
+ 'Your PHP "include_path" needs to be updated to include the '.
+ 'PHPExcel Classes directory.');
+
+ $dialog->setTitle(pht('Excel Export Not Configured'));
+ $dialog->appendChild(hsprintf(
+ '<p>%s</p>'.
+ '<br />'.
+ '<p>'.
+ '<a href="http://www.phpexcel.net/">http://www.phpexcel.net/</a>'.
+ '</p>'.
+ '<br />'.
+ '<p>%s</p>',
+ $inst1,
+ $inst2));
+
+ $dialog->addCancelButton('/phrequent/');
+ return id(new AphrontDialogResponse())->setDialog($dialog);
+ }
+
+ // TODO: PHPExcel has a dependency on the PHP zip extension. We should test
+ // for that here, since it fatals if we don't have the ZipArchive class.
+
+ $saved = id(new PhabricatorSavedQueryQuery())
+ ->setViewer($user)
+ ->withQueryKeys(array($this->key))
+ ->executeOne();
+ if (!$saved) {
+ $engine = id(new PhrequentSearchEngine())
+ ->setViewer($user);
+ if ($engine->isBuiltinQuery($this->key)) {
+ $saved = $engine->buildSavedQueryFromBuiltin($this->key);
+ }
+ if (!$saved) {
+ return new Aphront404Response();
+ }
+ }
+
+ $formats = PhrequentExcelFormat::loadAllFormats();
+ $export_formats = array();
+ foreach ($formats as $format_class => $format_object) {
+ $export_formats[$format_class] = $format_object->getName();
+ }
+
+ if (!$request->isDialogFormPost()) {
+ $dialog = new AphrontDialogView();
+ $dialog->setUser($user);
+
+ $dialog->setTitle(pht('Export User Time to Excel'));
+ $dialog->appendChild(phutil_tag('p', array(), pht(
+ 'Do you want to export the query results to Excel?')));
+
+ $form = id(new PHUIFormLayoutView())
+ ->appendChild(
+ id(new AphrontFormSelectControl())
+ ->setLabel(pht('Format:'))
+ ->setName('excel-format')
+ ->setOptions($export_formats));
+
+ $dialog->appendChild($form);
+
+ $dialog->addCancelButton('/phrequent/');
+ $dialog->addSubmitButton(pht('Export to Excel'));
+ return id(new AphrontDialogResponse())->setDialog($dialog);
+ }
+
+ $format = idx($formats, $request->getStr('excel-format'));
+ if ($format === null) {
+ throw new Exception('Excel format object not found.');
+ }
+
+ $saved->makeEphemeral();
+ $saved->setParameter('limit', PHP_INT_MAX);
+
+ $engine = id(new PhrequentSearchEngine())
+ ->setViewer($user);
+
+ $query = $engine->buildQueryFromSavedQuery($saved);
+ $query->setViewer($user);
+ $events = $query->execute();
+
+ $before_date = $saved->getParameter('before');
+ $after_date = $saved->getParameter('after');
+
+ if ($before_date || $after_date) {
+ foreach ($events as $event) {
+ if ($before_date && $event->getDateEnded() > $before_date) {
+ $event->setDateEnded($before_date);
+ }
+ if ($after_date && $event->getDateStarted() < $after_date) {
+ $event->setDateStarted($after_date);
+ }
+ }
+ }
+ /*
+ * array_merge(
+ array_mergev(mpull($all_tasks, 'getProjectPHIDs')),
+ mpull($all_revisions, 'getArcanistProjectPHID'));*/
+ $all_users = mpull($events, 'getUserPHID');
+ $all_objects = phid_group_by_type(mpull($events, 'getObjectPHID'));
+
+ $all_tasks = id(new ManiphestTaskQuery())
+ ->setViewer($user)
+ ->withPHIDS((array)array_unique($all_objects['TASK']))
+ ->execute();
+ $all_revisions = id(new DifferentialRevisionQuery())
+ ->setViewer($user)
+ ->withPHIDS((array)array_unique($all_objects['DREV']))
+ ->execute();
+ $all_repositories = id(new PhabricatorRepositoryQuery())
+ ->setViewer($user)
+ ->withPHIDs(array_unique(mpull($all_revisions, 'getRepositoryPHID')))
+ ->needProjectPHIDs(true)
+ ->execute();
+ $all_projects = array_merge(
+ array_mergev(mpull($all_tasks, 'getProjectPHIDs')),
+ array_mergev(mpull($all_repositories, 'getProjectPHIDs')));
+ $all_users = id(new PhabricatorPeopleQuery())
+ ->setViewer($user)
+ ->withPHIDS(array_unique($all_users))
+ ->execute();
+ $all_projects = id(new PhabricatorHandleQuery())
+ ->setViewer($user)
+ ->withPHIDs(array_unique($all_projects))
+ ->execute();
+
+ $handles = array_merge(
+ mpull($all_tasks, null, 'getPHID'),
+ mpull($all_revisions, null, 'getPHID'),
+ mpull($all_users, null, 'getPHID'),
+ mpull($all_projects, null, 'getPHID'),
+ mpull($all_repositories, null, 'getPHID'));
+ $workbook = new PHPExcel();
+ $format->buildWorkbook($workbook, $events, $handles, $user);
+ $writer = PHPExcel_IOFactory::createWriter($workbook, 'Excel2007');
+
+ ob_start();
+ $writer->save('php://output');
+ $data = ob_get_clean();
+
+ $mime = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
+
+ return id(new AphrontFileResponse())
+ ->setMimeType($mime)
+ ->setDownload($format->getFileName().'.xlsx')
+ ->setContent($data);
+ }
+}
diff --git a/src/applications/phrequent/controller/PhrequentListController.php b/src/applications/phrequent/controller/PhrequentListController.php
--- a/src/applications/phrequent/controller/PhrequentListController.php
+++ b/src/applications/phrequent/controller/PhrequentListController.php
@@ -21,5 +21,4 @@
return $this->delegateToController($controller);
}
-
}
diff --git a/src/applications/phrequent/export/PhrequentExcelDefaultFormat.php b/src/applications/phrequent/export/PhrequentExcelDefaultFormat.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phrequent/export/PhrequentExcelDefaultFormat.php
@@ -0,0 +1,143 @@
+<?php
+
+/**
+ * @group phrequent
+ */
+final class PhrequentExcelDefaultFormat extends PhrequentExcelFormat {
+
+ public function getName() {
+ return pht('Default');
+ }
+
+ public function getFileName() {
+ return 'phrequent_'.date('Ymd');
+ }
+
+ /**
+ * @phutil-external-symbol class PHPExcel
+ * @phutil-external-symbol class PHPExcel_IOFactory
+ * @phutil-external-symbol class PHPExcel_Style_NumberFormat
+ * @phutil-external-symbol class PHPExcel_Cell_DataType
+ */
+ public function buildWorkbook(
+ PHPExcel $workbook,
+ array $events,
+ array $handles,
+ PhabricatorUser $user) {
+
+ $sheet = $workbook->setActiveSheetIndex(0);
+ $sheet->setTitle(pht('User Time'));
+
+ $widths = array(
+ 20,
+ 30,
+ 40,
+ 15,
+ 15,
+ 10,
+ );
+
+ foreach ($widths as $col => $width) {
+ if ($width !== null) {
+ $sheet->getColumnDimension($this->col($col))->setWidth($width);
+ }
+ }
+
+ $status_map = ManiphestTaskStatus::getTaskStatusMap();
+ $pri_map = ManiphestTaskPriority::getTaskPriorityMap();
+
+ $date_format = null;
+
+ $rows = array();
+ $rows[] = array(
+ pht('User'),
+ pht('Object'),
+ pht('Projects'),
+ pht('Date Started'),
+ pht('Date Ended'),
+ pht('Hours')
+ );
+
+ $column_formats = array(
+ PHPExcel_Style_NumberFormat::FORMAT_TEXT,
+ PHPExcel_Style_NumberFormat::FORMAT_TEXT,
+ PHPExcel_Style_NumberFormat::FORMAT_TEXT,
+ PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD2,
+ PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD2,
+ '[h]:mm:ss',
+ );
+
+ $header_format = array(
+ 'font' => array(
+ 'bold' => true,
+ ),
+ );
+
+ foreach ($events as $event) {
+ $event_user = null;
+ if ($event->getUserPHID()) {
+ $event_user = $handles[$event->getUserPHID()]->getRealName();
+ }
+
+ $event_object = null;
+ $event_projects = array();
+ if ($event->getObjectPHID()) {
+ switch (phid_get_type($event->getObjectPHID())) {
+ case 'TASK':
+ $event_task = $handles[$event->getObjectPHID()];
+ foreach ($event_task->getProjectPHIDs() as $phid) {
+ $event_projects[] = $handles[$phid]->getName();
+ }
+ $event_projects = implode(', ', $event_projects);
+ $event_object = $event_task->getTitle();
+ break;
+ case 'DREV':
+ $event_revision = $handles[$event->getObjectPHID()];
+ $event_repository = $handles[$event_revision->getRepositoryPHID()];
+ foreach ($event_repository->getProjectPHIDs() as $phid) {
+ $event_projects[] = $handles[$phid]->getName();
+ }
+ $event_projects = implode(', ', $event_projects);
+ $event_object = $event_revision->getTitle();
+ break;
+ default:
+ $event_object = $handles[$event->getObjectPHID()]->getName();
+ $event_projects = pht('Unknown');
+ break;
+ }
+ }
+
+ $rows[] = array(
+ $event_user,
+ $event_object,
+ $event_projects,
+ $this->computeExcelDate($event->getDateStarted()),
+ $this->computeExcelDate($event->getDateEnded()),
+ ($event->getDateEnded() - $event->getDateStarted()) / 86400,
+ );
+ }
+
+ foreach ($rows as $row => $cols) {
+ foreach ($cols as $col => $spec) {
+ $cell_name = $this->col($col).($row + 1);
+ $cell = $sheet
+ ->setCellValue($cell_name, $spec, $return_cell = true);
+
+ if ($row == 0) {
+ $sheet->getStyle($cell_name)->applyFromArray($header_format);
+ }
+
+ $sheet
+ ->getStyle($cell_name)
+ ->getNumberFormat()
+ ->setFormatCode($column_formats[$col]);
+ }
+ }
+ }
+
+
+ private function col($n) {
+ return chr(ord('A') + $n);
+ }
+
+}
diff --git a/src/applications/phrequent/export/PhrequentExcelFormat.php b/src/applications/phrequent/export/PhrequentExcelFormat.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phrequent/export/PhrequentExcelFormat.php
@@ -0,0 +1,47 @@
+<?php
+
+/**
+ * @group phrequent
+ */
+abstract class PhrequentExcelFormat {
+
+ final public static function loadAllFormats() {
+ $classes = id(new PhutilSymbolLoader())
+ ->setAncestorClass(__CLASS__)
+ ->setConcreteOnly(true)
+ ->selectAndLoadSymbols();
+
+ $objects = array();
+ foreach ($classes as $class) {
+ $objects[$class['name']] = newv($class['name'], array());
+ }
+
+ $objects = msort($objects, 'getOrder');
+
+ return $objects;
+ }
+
+ public abstract function getName();
+ public abstract function getFileName();
+
+ public function getOrder() {
+ return 0;
+ }
+
+ protected function computeExcelDate($epoch) {
+ $seconds_per_day = (60 * 60 * 24);
+ $offset = ($seconds_per_day * 25569);
+
+ return ($epoch + $offset) / $seconds_per_day;
+ }
+
+ /**
+ * @phutil-external-symbol class PHPExcel
+ */
+ public abstract function buildWorkbook(
+ PHPExcel $workbook,
+ array $tasks,
+ array $handles,
+ PhabricatorUser $user);
+
+}
diff --git a/src/applications/phrequent/query/PhrequentSearchEngine.php b/src/applications/phrequent/query/PhrequentSearchEngine.php
--- a/src/applications/phrequent/query/PhrequentSearchEngine.php
+++ b/src/applications/phrequent/query/PhrequentSearchEngine.php
@@ -25,6 +25,22 @@
$saved->setParameter('order', $request->getStr('order'));
+ $saved->setParameter(
+ 'after',
+ id(new AphrontFormDateControl())
+ ->setName('after')
+ ->setAllowNull(true)
+ ->setUser($request->getUser())
+ ->readValueFromRequest($request));
+
+ $saved->setParameter(
+ 'before',
+ id(new AphrontFormDateControl())
+ ->setName('before')
+ ->setAllowNull(true)
+ ->setUser($request->getUser())
+ ->readValueFromRequest($request));
+
return $saved;
}
@@ -46,6 +62,16 @@
$query->setOrder($order);
}
+ $after = $saved->getParameter('after');
+ if ($after != null) {
+ $query->afterDate($after);
+ }
+
+ $before = $saved->getParameter('before');
+ if ($before != null) {
+ $query->beforeDate($before);
+ }
+
return $query;
}
@@ -53,11 +79,15 @@
AphrontFormView $form,
PhabricatorSavedQuery $saved_query) {
+ $user = $this->requireViewer();
+
$user_phids = $saved_query->getParameter('userPHIDs', array());
$ended = $saved_query->getParameter(
'ended', PhrequentUserTimeQuery::ENDED_ALL);
$order = $saved_query->getParameter(
'order', PhrequentUserTimeQuery::ORDER_ENDED_DESC);
+ $after = $saved_query->getParameter('after', null);
+ $before = $saved_query->getParameter('before', null);
$phids = array_merge($user_phids);
$handles = id(new PhabricatorHandleQuery())
@@ -83,7 +113,23 @@
->setLabel(pht('Order'))
->setName('order')
->setValue($order)
- ->setOptions(PhrequentUserTimeQuery::getOrderSearchOptions()));
+ ->setOptions(PhrequentUserTimeQuery::getOrderSearchOptions()))
+ ->appendChild(
+ id(new AphrontFormDateControl())
+ ->setLabel(pht('After'))
+ ->setName('after')
+ ->setUser($user)
+ ->setValue($after)
+ ->setAllowNull(true)
+ ->setInitialTime(AphrontFormDateControl::TIME_START_OF_DAY))
+ ->appendChild(
+ id(new AphrontFormDateControl())
+ ->setLabel(pht('Before'))
+ ->setName('before')
+ ->setUser($user)
+ ->setValue($before)
+ ->setAllowNull(true)
+ ->setInitialTime(AphrontFormDateControl::TIME_END_OF_DAY));
}
protected function getURI($path) {
@@ -173,6 +219,17 @@
pht(
'Ended on %s',
$time_ended));
+ if ($usertime->getObjectPHID() !== null &&
+ $usertime->getUserPHID() === $viewer->getPHID()) {
+ $item->addAction(
+ id(new PHUIListItemView())
+ ->setIcon('fa-pencil')
+ ->setRenderNameAsTooltip(true)
+ ->setName(pht('Edit'))
+ ->setHref($this->getApplicationURI(
+ '/edit/'.
+ $usertime->getId().'/')));
+ }
} else {
$item->addAttribute(
pht(
@@ -197,7 +254,37 @@
$view->addItem($item);
}
- return $view;
+ return phutil_tag(
+ 'div',
+ array(
+ 'class' => 'phrequent-list-container',
+ ),
+ array(
+ $view,
+ $this->renderListActions($query),
+ ));
+ }
+
+ private function renderListActions(PhabricatorSavedQuery $saved_query) {
+ $user = $this->getRequest()->getUser();
+
+ $export = javelin_tag(
+ 'a',
+ array(
+ 'href' => '/phrequent/export/'.$saved_query->getQueryKey().'/',
+ 'class' => 'grey button',
+ ),
+ pht('Export to Excel'));
+
+ require_celerity_resource('phrequent-css');
+
+ $actions = hsprintf(
+ '<ul class="phrequent-list-actions">'.
+ '<li>%s</li>'.
+ '</ul>',
+ $export);
+
+ return $actions;
}
}
diff --git a/src/applications/phrequent/query/PhrequentUserTimeQuery.php b/src/applications/phrequent/query/PhrequentUserTimeQuery.php
--- a/src/applications/phrequent/query/PhrequentUserTimeQuery.php
+++ b/src/applications/phrequent/query/PhrequentUserTimeQuery.php
@@ -16,13 +16,21 @@
const ENDED_NO = 1;
const ENDED_ALL = 2;
+ private $ids;
private $userPHIDs;
private $objectPHIDs;
+ private $afterDate;
+ private $beforeDate;
private $order = self::ORDER_ID_ASC;
private $ended = self::ENDED_ALL;
private $needPreemptingEvents;
+ public function withIDs($ids) {
+ $this->ids = $ids;
+ return $this;
+ }
+
public function withUserPHIDs($user_phids) {
$this->userPHIDs = $user_phids;
return $this;
@@ -33,6 +41,16 @@
return $this;
}
+ public function afterDate($after_date) {
+ $this->afterDate = $after_date;
+ return $this;
+ }
+
+ public function beforeDate($before_date) {
+ $this->beforeDate = $before_date;
+ return $this;
+ }
+
public function withEnded($ended) {
$this->ended = $ended;
return $this;
@@ -51,6 +69,13 @@
private function buildWhereClause(AphrontDatabaseConnection $conn) {
$where = array();
+ if ($this->ids) {
+ $where[] = qsprintf(
+ $conn,
+ 'id IN (%Ld)',
+ $this->ids);
+ }
+
if ($this->userPHIDs) {
$where[] = qsprintf(
$conn,
@@ -82,6 +107,20 @@
throw new Exception("Unknown ended '{$this->ended}'!");
}
+ if ($this->afterDate) {
+ $where[] = qsprintf(
+ $conn,
+ 'dateEnded > %d',
+ $this->afterDate);
+ }
+
+ if ($this->beforeDate) {
+ $where[] = qsprintf(
+ $conn,
+ 'dateStarted < %d',
+ $this->beforeDate);
+ }
+
$where[] = $this->buildPagingClause($conn);
return $this->formatWhereClause($where);
diff --git a/src/applications/phrequent/storage/PhrequentUserTime.php b/src/applications/phrequent/storage/PhrequentUserTime.php
--- a/src/applications/phrequent/storage/PhrequentUserTime.php
+++ b/src/applications/phrequent/storage/PhrequentUserTime.php
@@ -14,6 +14,7 @@
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
);
}
diff --git a/webroot/rsrc/css/application/phrequent/phrequent.css b/webroot/rsrc/css/application/phrequent/phrequent.css
--- a/webroot/rsrc/css/application/phrequent/phrequent.css
+++ b/webroot/rsrc/css/application/phrequent/phrequent.css
@@ -18,3 +18,11 @@
color: {$greytext};
background-image: url(/rsrc/image/phrequent_inactive.png);
}
+
+.phrequent-list-actions {
+ border: 1px solid #e7e7e7;
+ border-bottom: 1px solid #A1A6B0;
+ background: #fff;
+ margin: 0 16px;
+ padding: 10px 8px;
+}

File Metadata

Mime Type
text/plain
Expires
May 15 2024, 11:36 PM (4 w, 3 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6287601
Default Alt Text
D10162.diff (26 KB)

Event Timeline