diff --git a/src/applications/phrequent/controller/PhrequentTrackController.php b/src/applications/phrequent/controller/PhrequentTrackController.php
index 95e7c0d9f6..2b653b53aa 100644
--- a/src/applications/phrequent/controller/PhrequentTrackController.php
+++ b/src/applications/phrequent/controller/PhrequentTrackController.php
@@ -1,112 +1,165 @@
phid = $data['phid'];
$this->verb = $data['verb'];
}
public function processRequest() {
$request = $this->getRequest();
- $user = $request->getUser();
- $editor = new PhrequentTrackingEditor();
+ $viewer = $request->getUser();
$phid = $this->phid;
$handle = id(new PhabricatorHandleQuery())
- ->setViewer($user)
+ ->setViewer($viewer)
->withPHIDs(array($phid))
->executeOne();
+ $done_uri = $handle->getURI();
- if (!$this->isStartingTracking() &&
- !$this->isStoppingTracking()) {
- throw new Exception('Unrecognized verb: '.$this->verb);
- }
-
+ $current_timer = null;
switch ($this->verb) {
case 'start':
$button_text = pht('Start Tracking');
$title_text = pht('Start Tracking Time');
$inner_text = pht('What time did you start working?');
$action_text = pht('Start Timer');
$label_text = pht('Start Time');
break;
case 'stop':
$button_text = pht('Stop Tracking');
$title_text = pht('Stop Tracking Time');
$inner_text = pht('What time did you stop working?');
$action_text = pht('Stop Timer');
$label_text = pht('Stop Time');
+
+
+ $current_timer = id(new PhrequentUserTimeQuery())
+ ->setViewer($viewer)
+ ->withUserPHIDs(array($viewer->getPHID()))
+ ->withObjectPHIDs(array($phid))
+ ->withEnded(PhrequentUserTimeQuery::ENDED_NO)
+ ->executeOne();
+ if (!$current_timer) {
+ return $this->newDialog()
+ ->setTitle(pht('Not Tracking Time'))
+ ->appendParagraph(
+ pht(
+ 'You are not currently tracking time on this object.'))
+ ->addCancelButton($done_uri);
+ }
break;
+ default:
+ return new Aphront404Response();
}
+ $errors = array();
+ $v_note = null;
+ $e_date = null;
+
$epoch_control = id(new AphrontFormDateControl())
- ->setUser($user)
+ ->setUser($viewer)
->setName('epoch')
->setLabel($action_text)
->setValue(time());
- $err = array();
-
if ($request->isDialogFormPost()) {
+ $v_note = $request->getStr('note');
$timestamp = $epoch_control->readValueFromRequest($request);
- $note = $request->getStr('note');
- if (!$epoch_control->isValid() || $timestamp > time()) {
- $err[] = pht('Invalid date, please enter a valid non-future date');
+ if (!$epoch_control->isValid()) {
+ $errors[] = pht('Please choose an valid date.');
+ $e_date = pht('Invalid');
+ } else {
+ $max_time = PhabricatorTime::getNow();
+ if ($timestamp > $max_time) {
+ if ($this->isStoppingTracking()) {
+ $errors[] = pht(
+ 'You can not stop tracking time at a future time. Enter the '.
+ 'current time, or a time in the past.');
+ } else {
+ $errors[] = pht(
+ 'You can not start tracking time at a future time. Enter the '.
+ 'current time, or a time in the past.');
+ }
+ $e_date = pht('Invalid');
+ }
+
+ if ($this->isStoppingTracking()) {
+ $min_time = $current_timer->getDateStarted();
+ if ($min_time > $timestamp) {
+ $errors[] = pht(
+ 'Stop time must be after start time.');
+ $e_date = pht('Invalid');
+ }
+ }
}
- if (!$err) {
+ if (!$errors) {
+ $editor = new PhrequentTrackingEditor();
if ($this->isStartingTracking()) {
- $editor->startTracking($user, $this->phid, $timestamp);
+ $editor->startTracking($viewer, $this->phid, $timestamp);
} else if ($this->isStoppingTracking()) {
- $editor->stopTracking($user, $this->phid, $timestamp, $note);
+ $editor->stopTracking($viewer, $this->phid, $timestamp, $v_note);
}
- return id(new AphrontRedirectResponse());
+
+ return id(new AphrontRedirectResponse())->setURI($done_uri);
}
}
+ $epoch_control->setError($e_date);
+
$dialog = $this->newDialog()
->setTitle($title_text)
- ->setWidth(AphrontDialogView::WIDTH_FORM);
-
- if ($err) {
- $dialog->setErrors($err);
- }
+ ->setWidth(AphrontDialogView::WIDTH_FORM)
+ ->setErrors($errors)
+ ->appendParagraph($inner_text);
$form = new PHUIFormLayoutView();
- $form
- ->appendChild(hsprintf(
- '
%s
', $inner_text));
+
+ if ($this->isStoppingTracking()) {
+ $start_time = $current_timer->getDateStarted();
+ $start_string = pht(
+ '%s (%s ago)',
+ phabricator_datetime($start_time, $viewer),
+ phutil_format_relative_time(PhabricatorTime::getNow() - $start_time));
+
+ $form->appendChild(
+ id(new AphrontFormStaticControl())
+ ->setLabel(pht('Started At'))
+ ->setValue($start_string));
+ }
$form->appendChild($epoch_control);
if ($this->isStoppingTracking()) {
- $form
- ->appendChild(
- id(new AphrontFormTextControl())
- ->setLabel(pht('Note'))
- ->setName('note'));
+ $form->appendChild(
+ id(new AphrontFormTextControl())
+ ->setLabel(pht('Note'))
+ ->setName('note')
+ ->setValue($v_note));
}
$dialog->appendChild($form);
- $dialog->addCancelButton($handle->getURI());
+ $dialog->addCancelButton($done_uri);
+
$dialog->addSubmitButton($action_text);
return $dialog;
}
private function isStartingTracking() {
return $this->verb === 'start';
}
private function isStoppingTracking() {
return $this->verb === 'stop';
}
}
diff --git a/src/applications/phrequent/event/PhrequentUIEventListener.php b/src/applications/phrequent/event/PhrequentUIEventListener.php
index 9b0bdace6b..9987bcfd03 100644
--- a/src/applications/phrequent/event/PhrequentUIEventListener.php
+++ b/src/applications/phrequent/event/PhrequentUIEventListener.php
@@ -1,153 +1,151 @@
listen(PhabricatorEventType::TYPE_UI_DIDRENDERACTIONS);
$this->listen(PhabricatorEventType::TYPE_UI_WILLRENDERPROPERTIES);
}
public function handleEvent(PhutilEvent $event) {
switch ($event->getType()) {
case PhabricatorEventType::TYPE_UI_DIDRENDERACTIONS:
$this->handleActionEvent($event);
break;
case PhabricatorEventType::TYPE_UI_WILLRENDERPROPERTIES:
$this->handlePropertyEvent($event);
break;
}
}
private function handleActionEvent($event) {
$user = $event->getUser();
$object = $event->getValue('object');
if (!$object || !$object->getPHID()) {
// No object, or the object has no PHID yet..
return;
}
if (!($object instanceof PhrequentTrackableInterface)) {
// This object isn't a time trackable object.
return;
}
if (!$this->canUseApplication($event->getUser())) {
return;
}
$tracking = PhrequentUserTimeQuery::isUserTrackingObject(
$user,
$object->getPHID());
if (!$tracking) {
$track_action = id(new PhabricatorActionView())
->setName(pht('Start Tracking Time'))
->setIcon('fa-clock-o')
->setWorkflow(true)
- ->setRenderAsForm(true)
->setHref('/phrequent/track/start/'.$object->getPHID().'/');
} else {
$track_action = id(new PhabricatorActionView())
->setName(pht('Stop Tracking Time'))
->setIcon('fa-clock-o red')
->setWorkflow(true)
- ->setRenderAsForm(true)
->setHref('/phrequent/track/stop/'.$object->getPHID().'/');
}
if (!$user->isLoggedIn()) {
$track_action->setDisabled(true);
}
$this->addActionMenuItems($event, $track_action);
}
private function handlePropertyEvent($ui_event) {
$user = $ui_event->getUser();
$object = $ui_event->getValue('object');
if (!$object || !$object->getPHID()) {
// No object, or the object has no PHID yet..
return;
}
if (!($object instanceof PhrequentTrackableInterface)) {
// This object isn't a time trackable object.
return;
}
if (!$this->canUseApplication($ui_event->getUser())) {
return;
}
$events = id(new PhrequentUserTimeQuery())
->setViewer($user)
->withObjectPHIDs(array($object->getPHID()))
->needPreemptingEvents(true)
->execute();
$event_groups = mgroup($events, 'getUserPHID');
if (!$events) {
return;
}
$handles = id(new PhabricatorHandleQuery())
->setViewer($user)
->withPHIDs(array_keys($event_groups))
->execute();
$status_view = new PHUIStatusListView();
foreach ($event_groups as $user_phid => $event_group) {
$item = new PHUIStatusItemView();
$item->setTarget($handles[$user_phid]->renderLink());
$state = 'stopped';
foreach ($event_group as $event) {
if ($event->getDateEnded() === null) {
if ($event->isPreempted()) {
$state = 'suspended';
} else {
$state = 'active';
break;
}
}
}
switch ($state) {
case 'active':
$item->setIcon(
PHUIStatusItemView::ICON_CLOCK,
'green',
pht('Working Now'));
break;
case 'suspended':
$item->setIcon(
PHUIStatusItemView::ICON_CLOCK,
'yellow',
pht('Interrupted'));
break;
case 'stopped':
$item->setIcon(
PHUIStatusItemView::ICON_CLOCK,
'bluegrey',
pht('Not Working Now'));
break;
}
$block = new PhrequentTimeBlock($event_group);
$item->setNote(
phutil_format_relative_time(
$block->getTimeSpentOnObject(
$object->getPHID(),
time())));
$status_view->addItem($item);
}
$view = $ui_event->getValue('view');
$view->addProperty(pht('Time Spent'), $status_view);
}
}