Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15409592
D10162.id24449.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
26 KB
Referenced Files
None
Subscribers
None
D10162.id24449.diff
View Options
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
Details
Attached
Mime Type
text/plain
Expires
Thu, Mar 20, 4:44 AM (5 d, 2 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7452734
Default Alt Text
D10162.id24449.diff (26 KB)
Attached To
Mode
D10162: Extends Phrequent search capabilities
Attached
Detach File
Event Timeline
Log In to Comment