diff --git a/src/applications/almanac/controller/AlmanacBindingEditController.php b/src/applications/almanac/controller/AlmanacBindingEditController.php index 35179c833b..ad6936fa70 100644 --- a/src/applications/almanac/controller/AlmanacBindingEditController.php +++ b/src/applications/almanac/controller/AlmanacBindingEditController.php @@ -1,128 +1,123 @@ getViewer(); $id = $request->getURIData('id'); if ($id) { $binding = id(new AlmanacBindingQuery()) ->setViewer($viewer) ->withIDs(array($id)) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, )) ->executeOne(); if (!$binding) { return new Aphront404Response(); } $service = $binding->getService(); $is_new = false; $service_uri = $service->getURI(); $cancel_uri = $binding->getURI(); $title = pht('Edit Binding'); $save_button = pht('Save Changes'); } else { $service = id(new AlmanacServiceQuery()) ->setViewer($viewer) ->withIDs(array($request->getStr('serviceID'))) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, )) ->executeOne(); $binding = AlmanacBinding::initializeNewBinding($service); $is_new = true; $service_uri = $service->getURI(); $cancel_uri = $service_uri; $title = pht('Create Binding'); $save_button = pht('Create Binding'); } $v_interface = array(); if ($binding->getInterfacePHID()) { $v_interface = array($binding->getInterfacePHID()); } $e_interface = true; $validation_exception = null; if ($request->isFormPost()) { $v_interface = $request->getArr('interfacePHIDs'); $type_interface = AlmanacBindingTransaction::TYPE_INTERFACE; $xactions = array(); $xactions[] = id(new AlmanacBindingTransaction()) ->setTransactionType($type_interface) ->setNewValue(head($v_interface)); $editor = id(new AlmanacBindingEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true); try { $editor->applyTransactions($binding, $xactions); $binding_uri = $binding->getURI(); return id(new AphrontRedirectResponse())->setURI($binding_uri); } catch (PhabricatorApplicationTransactionValidationException $ex) { $validation_exception = $ex; $e_interface = $ex->getShortMessage($type_interface); } } - $interface_handles = array(); - if ($v_interface) { - $interface_handles = $this->loadViewerHandles($v_interface); - } - $form = id(new AphrontFormView()) ->setUser($viewer) - ->appendChild( + ->appendControl( id(new AphrontFormTokenizerControl()) ->setName('interfacePHIDs') ->setLabel('Interface') ->setLimit(1) ->setDatasource(new AlmanacInterfaceDatasource()) - ->setValue($interface_handles) + ->setValue($v_interface) ->setError($e_interface)) ->appendChild( id(new AphrontFormSubmitControl()) ->addCancelButton($cancel_uri) ->setValue($save_button)); $box = id(new PHUIObjectBoxView()) ->setValidationException($validation_exception) ->setHeaderText($title) ->appendChild($form); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($service->getName(), $service_uri); if ($is_new) { $crumbs->addTextCrumb(pht('Create Binding')); } else { $crumbs->addTextCrumb(pht('Edit Binding')); } return $this->buildApplicationPage( array( $crumbs, $box, ), array( 'title' => $title, )); } } diff --git a/src/applications/almanac/controller/AlmanacDeviceEditController.php b/src/applications/almanac/controller/AlmanacDeviceEditController.php index 149d9cab37..4dc56a4234 100644 --- a/src/applications/almanac/controller/AlmanacDeviceEditController.php +++ b/src/applications/almanac/controller/AlmanacDeviceEditController.php @@ -1,170 +1,164 @@ getViewer(); $list_uri = $this->getApplicationURI('device/'); $id = $request->getURIData('id'); if ($id) { $device = id(new AlmanacDeviceQuery()) ->setViewer($viewer) ->withIDs(array($id)) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, )) ->executeOne(); if (!$device) { return new Aphront404Response(); } $is_new = false; $device_uri = $device->getURI(); $cancel_uri = $device_uri; $title = pht('Edit Device'); $save_button = pht('Save Changes'); } else { $this->requireApplicationCapability( AlmanacCreateDevicesCapability::CAPABILITY); $device = AlmanacDevice::initializeNewDevice(); $is_new = true; $cancel_uri = $list_uri; $title = pht('Create Device'); $save_button = pht('Create Device'); } $v_name = $device->getName(); $e_name = true; $validation_exception = null; if ($is_new) { $v_projects = array(); } else { $v_projects = PhabricatorEdgeQuery::loadDestinationPHIDs( $device->getPHID(), PhabricatorProjectObjectHasProjectEdgeType::EDGECONST); $v_projects = array_reverse($v_projects); } if ($request->isFormPost()) { $v_name = $request->getStr('name'); $v_view = $request->getStr('viewPolicy'); $v_edit = $request->getStr('editPolicy'); $v_projects = $request->getArr('projects'); $type_name = AlmanacDeviceTransaction::TYPE_NAME; $type_view = PhabricatorTransactions::TYPE_VIEW_POLICY; $type_edit = PhabricatorTransactions::TYPE_EDIT_POLICY; $xactions = array(); $xactions[] = id(new AlmanacDeviceTransaction()) ->setTransactionType($type_name) ->setNewValue($v_name); $xactions[] = id(new AlmanacDeviceTransaction()) ->setTransactionType($type_view) ->setNewValue($v_view); $xactions[] = id(new AlmanacDeviceTransaction()) ->setTransactionType($type_edit) ->setNewValue($v_edit); $proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST; $xactions[] = id(new AlmanacDeviceTransaction()) ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) ->setMetadataValue('edge:type', $proj_edge_type) ->setNewValue(array('=' => array_fuse($v_projects))); $editor = id(new AlmanacDeviceEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true); try { $editor->applyTransactions($device, $xactions); $device_uri = $device->getURI(); return id(new AphrontRedirectResponse())->setURI($device_uri); } catch (PhabricatorApplicationTransactionValidationException $ex) { $validation_exception = $ex; $e_name = $ex->getShortMessage($type_name); $device->setViewPolicy($v_view); $device->setEditPolicy($v_edit); } } $policies = id(new PhabricatorPolicyQuery()) ->setViewer($viewer) ->setObject($device) ->execute(); - if ($v_projects) { - $project_handles = $this->loadViewerHandles($v_projects); - } else { - $project_handles = array(); - } - $form = id(new AphrontFormView()) ->setUser($viewer) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Name')) ->setName('name') ->setValue($v_name) ->setError($e_name)) ->appendChild( id(new AphrontFormPolicyControl()) ->setName('viewPolicy') ->setPolicyObject($device) ->setCapability(PhabricatorPolicyCapability::CAN_VIEW) ->setPolicies($policies)) ->appendChild( id(new AphrontFormPolicyControl()) ->setName('editPolicy') ->setPolicyObject($device) ->setCapability(PhabricatorPolicyCapability::CAN_EDIT) ->setPolicies($policies)) - ->appendChild( + ->appendControl( id(new AphrontFormTokenizerControl()) ->setLabel(pht('Projects')) ->setName('projects') - ->setValue($project_handles) + ->setValue($v_projects) ->setDatasource(new PhabricatorProjectDatasource())) ->appendChild( id(new AphrontFormSubmitControl()) ->addCancelButton($cancel_uri) ->setValue($save_button)); $box = id(new PHUIObjectBoxView()) ->setValidationException($validation_exception) ->setHeaderText($title) ->appendChild($form); $crumbs = $this->buildApplicationCrumbs(); if ($is_new) { $crumbs->addTextCrumb(pht('Create Device')); } else { $crumbs->addTextCrumb($device->getName(), $device_uri); $crumbs->addTextCrumb(pht('Edit')); } return $this->buildApplicationPage( array( $crumbs, $box, ), array( 'title' => $title, )); } } diff --git a/src/applications/almanac/controller/AlmanacServiceEditController.php b/src/applications/almanac/controller/AlmanacServiceEditController.php index a0db56560c..13f31430e7 100644 --- a/src/applications/almanac/controller/AlmanacServiceEditController.php +++ b/src/applications/almanac/controller/AlmanacServiceEditController.php @@ -1,263 +1,257 @@ getViewer(); $list_uri = $this->getApplicationURI('service/'); $id = $request->getURIData('id'); if ($id) { $service = id(new AlmanacServiceQuery()) ->setViewer($viewer) ->withIDs(array($id)) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, )) ->executeOne(); if (!$service) { return new Aphront404Response(); } $is_new = false; $service_uri = $service->getURI(); $cancel_uri = $service_uri; $title = pht('Edit Service'); $save_button = pht('Save Changes'); } else { $cancel_uri = $list_uri; $this->requireApplicationCapability( AlmanacCreateServicesCapability::CAPABILITY); $service_class = $request->getStr('serviceClass'); $service_types = AlmanacServiceType::getAllServiceTypes(); if (empty($service_types[$service_class])) { return $this->buildServiceTypeResponse($service_types, $cancel_uri); } $service_type = $service_types[$service_class]; if ($service_type->isClusterServiceType()) { $this->requireApplicationCapability( AlmanacCreateClusterServicesCapability::CAPABILITY); } $service = AlmanacService::initializeNewService(); $service->setServiceClass($service_class); $service->attachServiceType($service_type); $is_new = true; $title = pht('Create Service'); $save_button = pht('Create Service'); } $v_name = $service->getName(); $e_name = true; $validation_exception = null; if ($is_new) { $v_projects = array(); } else { $v_projects = PhabricatorEdgeQuery::loadDestinationPHIDs( $service->getPHID(), PhabricatorProjectObjectHasProjectEdgeType::EDGECONST); $v_projects = array_reverse($v_projects); } if ($request->isFormPost() && $request->getStr('edit')) { $v_name = $request->getStr('name'); $v_view = $request->getStr('viewPolicy'); $v_edit = $request->getStr('editPolicy'); $v_projects = $request->getArr('projects'); $type_name = AlmanacServiceTransaction::TYPE_NAME; $type_view = PhabricatorTransactions::TYPE_VIEW_POLICY; $type_edit = PhabricatorTransactions::TYPE_EDIT_POLICY; $xactions = array(); $xactions[] = id(new AlmanacServiceTransaction()) ->setTransactionType($type_name) ->setNewValue($v_name); $xactions[] = id(new AlmanacServiceTransaction()) ->setTransactionType($type_view) ->setNewValue($v_view); $xactions[] = id(new AlmanacServiceTransaction()) ->setTransactionType($type_edit) ->setNewValue($v_edit); $proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST; $xactions[] = id(new AlmanacServiceTransaction()) ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) ->setMetadataValue('edge:type', $proj_edge_type) ->setNewValue(array('=' => array_fuse($v_projects))); $editor = id(new AlmanacServiceEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true); try { $editor->applyTransactions($service, $xactions); $service_uri = $service->getURI(); return id(new AphrontRedirectResponse())->setURI($service_uri); } catch (PhabricatorApplicationTransactionValidationException $ex) { $validation_exception = $ex; $e_name = $ex->getShortMessage($type_name); $service->setViewPolicy($v_view); $service->setEditPolicy($v_edit); } } $policies = id(new PhabricatorPolicyQuery()) ->setViewer($viewer) ->setObject($service) ->execute(); - if ($v_projects) { - $project_handles = $this->loadViewerHandles($v_projects); - } else { - $project_handles = array(); - } - $form = id(new AphrontFormView()) ->setUser($viewer) ->addHiddenInput('edit', true) ->addHiddenInput('serviceClass', $service->getServiceClass()) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Name')) ->setName('name') ->setValue($v_name) ->setError($e_name)) ->appendChild( id(new AphrontFormPolicyControl()) ->setName('viewPolicy') ->setPolicyObject($service) ->setCapability(PhabricatorPolicyCapability::CAN_VIEW) ->setPolicies($policies)) ->appendChild( id(new AphrontFormPolicyControl()) ->setName('editPolicy') ->setPolicyObject($service) ->setCapability(PhabricatorPolicyCapability::CAN_EDIT) ->setPolicies($policies)) - ->appendChild( + ->appendControl( id(new AphrontFormTokenizerControl()) ->setLabel(pht('Projects')) ->setName('projects') - ->setValue($project_handles) + ->setValue($v_projects) ->setDatasource(new PhabricatorProjectDatasource())) ->appendChild( id(new AphrontFormSubmitControl()) ->addCancelButton($cancel_uri) ->setValue($save_button)); $box = id(new PHUIObjectBoxView()) ->setValidationException($validation_exception) ->setHeaderText($title) ->appendChild($form); $crumbs = $this->buildApplicationCrumbs(); if ($is_new) { $crumbs->addTextCrumb(pht('Create Service')); } else { $crumbs->addTextCrumb($service->getName(), $service_uri); $crumbs->addTextCrumb(pht('Edit')); } return $this->buildApplicationPage( array( $crumbs, $box, ), array( 'title' => $title, )); } private function buildServiceTypeResponse(array $service_types, $cancel_uri) { $request = $this->getRequest(); $viewer = $this->getViewer(); $e_service = null; $errors = array(); if ($request->isFormPost()) { $e_service = pht('Required'); $errors[] = pht( 'To create a new service, you must select a service type.'); } list($can_cluster, $cluster_link) = $this->explainApplicationCapability( AlmanacCreateClusterServicesCapability::CAPABILITY, pht('You have permission to create cluster services.'), pht('You do not have permission to create new cluster services.')); $type_control = id(new AphrontFormRadioButtonControl()) ->setLabel(pht('Service Type')) ->setName('serviceClass') ->setError($e_service); foreach ($service_types as $service_type) { $is_cluster = $service_type->isClusterServiceType(); $is_disabled = ($is_cluster && !$can_cluster); if ($is_cluster) { $extra = $cluster_link; } else { $extra = null; } $type_control->addButton( get_class($service_type), $service_type->getServiceTypeName(), array( $service_type->getServiceTypeDescription(), $extra, ), $is_disabled ? 'disabled' : null, $is_disabled); } $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Create Service')); $title = pht('Choose Service Type'); $form = id(new AphrontFormView()) ->setUser($viewer) ->appendChild($type_control) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue(pht('Continue')) ->addCancelButton($cancel_uri)); $box = id(new PHUIObjectBoxView()) ->setFormErrors($errors) ->setHeaderText($title) ->appendChild($form); return $this->buildApplicationPage( array( $crumbs, $box, ), array( 'title' => $title, )); } } diff --git a/src/applications/audit/query/PhabricatorCommitSearchEngine.php b/src/applications/audit/query/PhabricatorCommitSearchEngine.php index 4e8dfd7d08..bfaaf3b234 100644 --- a/src/applications/audit/query/PhabricatorCommitSearchEngine.php +++ b/src/applications/audit/query/PhabricatorCommitSearchEngine.php @@ -1,225 +1,213 @@ setParameter( 'auditorPHIDs', $this->readPHIDsFromRequest($request, 'auditorPHIDs')); $saved->setParameter( 'commitAuthorPHIDs', $this->readUsersFromRequest($request, 'authors')); $saved->setParameter( 'auditStatus', $request->getStr('auditStatus')); $saved->setParameter( 'repositoryPHIDs', $this->readPHIDsFromRequest($request, 'repositoryPHIDs')); // -- TODO - T4173 - file location return $saved; } public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { $query = id(new DiffusionCommitQuery()) ->needAuditRequests(true) ->needCommitData(true); $auditor_phids = $saved->getParameter('auditorPHIDs', array()); if ($auditor_phids) { $query->withAuditorPHIDs($auditor_phids); } $commit_author_phids = $saved->getParameter('commitAuthorPHIDs', array()); if ($commit_author_phids) { $query->withAuthorPHIDs($commit_author_phids); } $audit_status = $saved->getParameter('auditStatus', null); if ($audit_status) { $query->withAuditStatus($audit_status); } $awaiting_user_phid = $saved->getParameter('awaitingUserPHID', null); if ($awaiting_user_phid) { // This is used only for the built-in "needs attention" filter, // so cheat and just use the already-loaded viewer rather than reloading // it. $query->withAuditAwaitingUser($this->requireViewer()); } $repository_phids = $saved->getParameter('repositoryPHIDs', array()); if ($repository_phids) { $query->withRepositoryPHIDs($repository_phids); } return $query; } public function buildSearchForm( AphrontFormView $form, PhabricatorSavedQuery $saved) { $auditor_phids = $saved->getParameter('auditorPHIDs', array()); $commit_author_phids = $saved->getParameter( 'commitAuthorPHIDs', array()); $audit_status = $saved->getParameter('auditStatus', null); $repository_phids = $saved->getParameter('repositoryPHIDs', array()); - $phids = array_mergev( - array( - $auditor_phids, - $commit_author_phids, - $repository_phids, - )); - - $handles = id(new PhabricatorHandleQuery()) - ->setViewer($this->requireViewer()) - ->withPHIDs($phids) - ->execute(); - $form - ->appendChild( + ->appendControl( id(new AphrontFormTokenizerControl()) ->setDatasource(new DiffusionAuditorDatasource()) ->setName('auditorPHIDs') ->setLabel(pht('Auditors')) - ->setValue(array_select_keys($handles, $auditor_phids))) - ->appendChild( + ->setValue($auditor_phids)) + ->appendControl( id(new AphrontFormTokenizerControl()) ->setDatasource(new PhabricatorPeopleDatasource()) ->setName('authors') ->setLabel(pht('Commit Authors')) - ->setValue(array_select_keys($handles, $commit_author_phids))) + ->setValue($commit_author_phids)) ->appendChild( id(new AphrontFormSelectControl()) - ->setName('auditStatus') - ->setLabel(pht('Audit Status')) - ->setOptions($this->getAuditStatusOptions()) - ->setValue($audit_status)) - ->appendChild( + ->setName('auditStatus') + ->setLabel(pht('Audit Status')) + ->setOptions($this->getAuditStatusOptions()) + ->setValue($audit_status)) + ->appendControl( id(new AphrontFormTokenizerControl()) - ->setLabel(pht('Repositories')) - ->setName('repositoryPHIDs') - ->setDatasource(new DiffusionRepositoryDatasource()) - ->setValue(array_select_keys($handles, $repository_phids))); + ->setLabel(pht('Repositories')) + ->setName('repositoryPHIDs') + ->setDatasource(new DiffusionRepositoryDatasource()) + ->setValue($repository_phids)); } protected function getURI($path) { return '/audit/'.$path; } protected function getBuiltinQueryNames() { $names = array(); if ($this->requireViewer()->isLoggedIn()) { $names['need'] = pht('Need Attention'); $names['problem'] = pht('Problem Commits'); } $names['open'] = pht('Open Audits'); if ($this->requireViewer()->isLoggedIn()) { $names['authored'] = pht('Authored Commits'); } $names['all'] = pht('All Commits'); return $names; } public function buildSavedQueryFromBuiltin($query_key) { $query = $this->newSavedQuery(); $query->setQueryKey($query_key); $viewer = $this->requireViewer(); switch ($query_key) { case 'all': return $query; case 'open': $query->setParameter( 'auditStatus', DiffusionCommitQuery::AUDIT_STATUS_OPEN); return $query; case 'need': $query->setParameter('awaitingUserPHID', $viewer->getPHID()); $query->setParameter( 'auditStatus', DiffusionCommitQuery::AUDIT_STATUS_OPEN); $query->setParameter( 'auditorPHIDs', PhabricatorAuditCommentEditor::loadAuditPHIDsForUser($viewer)); return $query; case 'authored': $query->setParameter('commitAuthorPHIDs', array($viewer->getPHID())); return $query; case 'problem': $query->setParameter('commitAuthorPHIDs', array($viewer->getPHID())); $query->setParameter( 'auditStatus', DiffusionCommitQuery::AUDIT_STATUS_CONCERN); return $query; } return parent::buildSavedQueryFromBuiltin($query_key); } private function getAuditStatusOptions() { return array( DiffusionCommitQuery::AUDIT_STATUS_ANY => pht('Any'), DiffusionCommitQuery::AUDIT_STATUS_OPEN => pht('Open'), DiffusionCommitQuery::AUDIT_STATUS_CONCERN => pht('Concern Raised'), DiffusionCommitQuery::AUDIT_STATUS_ACCEPTED => pht('Accepted'), DiffusionCommitQuery::AUDIT_STATUS_PARTIAL => pht('Partially Audited'), ); } protected function renderResultList( array $commits, PhabricatorSavedQuery $query, array $handles) { assert_instances_of($commits, 'PhabricatorRepositoryCommit'); $viewer = $this->requireViewer(); $nodata = pht('No matching audits.'); $view = id(new PhabricatorAuditListView()) ->setUser($viewer) ->setCommits($commits) ->setAuthorityPHIDs( PhabricatorAuditCommentEditor::loadAuditPHIDsForUser($viewer)) ->setNoDataString($nodata); $phids = $view->getRequiredHandlePHIDs(); if ($phids) { $handles = id(new PhabricatorHandleQuery()) ->setViewer($viewer) ->withPHIDs($phids) ->execute(); } else { $handles = array(); } $view->setHandles($handles); return $view->buildList(); } } diff --git a/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php b/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php index 62e4a08a59..936bd023e1 100644 --- a/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php +++ b/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php @@ -1,227 +1,211 @@ setParameter( 'rangeStart', $this->readDateFromRequest($request, 'rangeStart')); $saved->setParameter( 'rangeEnd', $this->readDateFromRequest($request, 'rangeEnd')); $saved->setParameter( 'upcoming', $this->readBoolFromRequest($request, 'upcoming')); $saved->setParameter( 'invitedPHIDs', $this->readUsersFromRequest($request, 'invited')); $saved->setParameter( 'creatorPHIDs', $this->readUsersFromRequest($request, 'creators')); return $saved; } public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { $query = id(new PhabricatorCalendarEventQuery()); $min_range = null; $max_range = null; if ($saved->getParameter('rangeStart')) { $min_range = $saved->getParameter('rangeStart'); } if ($saved->getParameter('rangeEnd')) { $max_range = $saved->getParameter('rangeEnd'); } if ($saved->getParameter('upcoming')) { if ($min_range) { $min_range = max(time(), $min_range); } else { $min_range = time(); } } if ($min_range || $max_range) { $query->withDateRange($min_range, $max_range); } $invited_phids = $saved->getParameter('invitedPHIDs'); if ($invited_phids) { $query->withInvitedPHIDs($invited_phids); } $creator_phids = $saved->getParameter('creatorPHIDs'); if ($creator_phids) { $query->withCreatorPHIDs($creator_phids); } return $query; } public function buildSearchForm( AphrontFormView $form, PhabricatorSavedQuery $saved) { $range_start = $saved->getParameter('rangeStart'); $range_end = $saved->getParameter('rangeEnd'); $upcoming = $saved->getParameter('upcoming'); $invited_phids = $saved->getParameter('invitedPHIDs', array()); $creator_phids = $saved->getParameter('creatorPHIDs', array()); - $all_phids = array_merge( - $invited_phids, - $creator_phids); - - if ($all_phids) { - $handles = id(new PhabricatorHandleQuery()) - ->setViewer($this->requireViewer()) - ->withPHIDs($all_phids) - ->execute(); - } else { - $handles = array(); - } - - $invited_handles = array_select_keys($handles, $invited_phids); - $creator_handles = array_select_keys($handles, $creator_phids); - $form - ->appendChild( + ->appendControl( id(new AphrontFormTokenizerControl()) ->setDatasource(new PhabricatorPeopleDatasource()) ->setName('creators') ->setLabel(pht('Created By')) - ->setValue($creator_handles)) - ->appendChild( + ->setValue($creator_phids)) + ->appendControl( id(new AphrontFormTokenizerControl()) ->setDatasource(new PhabricatorPeopleDatasource()) ->setName('invited') ->setLabel(pht('Invited')) - ->setValue($invited_handles)) + ->setValue($invited_phids)) ->appendChild( id(new AphrontFormDateControl()) ->setLabel(pht('Occurs After')) ->setUser($this->requireViewer()) ->setName('rangeStart') ->setAllowNull(true) ->setValue($range_start)) ->appendChild( id(new AphrontFormDateControl()) ->setLabel(pht('Occurs Before')) ->setUser($this->requireViewer()) ->setName('rangeEnd') ->setAllowNull(true) ->setValue($range_end)) ->appendChild( id(new AphrontFormCheckboxControl()) ->addCheckbox( 'upcoming', 1, pht('Show only upcoming events.'), $upcoming)); } protected function getURI($path) { return '/calendar/event/'.$path; } protected function getBuiltinQueryNames() { $names = array( 'upcoming' => pht('Upcoming Events'), 'all' => pht('All Events'), ); return $names; } public function buildSavedQueryFromBuiltin($query_key) { $query = $this->newSavedQuery(); $query->setQueryKey($query_key); switch ($query_key) { case 'upcoming': return $query->setParameter('upcoming', true); case 'all': return $query; } return parent::buildSavedQueryFromBuiltin($query_key); } protected function getRequiredHandlePHIDsForResultList( array $objects, PhabricatorSavedQuery $query) { $phids = array(); foreach ($objects as $event) { $phids[$event->getUserPHID()] = 1; } return array_keys($phids); } 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; } } diff --git a/src/view/form/AphrontFormView.php b/src/view/form/AphrontFormView.php index 59d3a6f24d..f680800f59 100644 --- a/src/view/form/AphrontFormView.php +++ b/src/view/form/AphrontFormView.php @@ -1,135 +1,156 @@ metadata = $metadata; return $this; } public function getMetadata() { return $this->metadata; } public function setID($id) { $this->id = $id; return $this; } public function setAction($action) { $this->action = $action; return $this; } public function setMethod($method) { $this->method = $method; return $this; } public function setEncType($enc_type) { $this->encType = $enc_type; return $this; } public function setShaded($shaded) { $this->shaded = $shaded; return $this; } public function addHiddenInput($key, $value) { $this->data[$key] = $value; return $this; } public function setWorkflow($workflow) { $this->workflow = $workflow; return $this; } public function addSigil($sigil) { $this->sigils[] = $sigil; return $this; } public function appendInstructions($text) { return $this->appendChild( phutil_tag( 'div', array( 'class' => 'aphront-form-instructions', ), $text)); } public function appendRemarkupInstructions($remarkup) { return $this->appendInstructions( PhabricatorMarkupEngine::renderOneObject( id(new PhabricatorMarkupOneOff())->setContent($remarkup), 'default', $this->getUser())); } public function buildLayoutView() { return id(new PHUIFormLayoutView()) ->appendChild($this->renderDataInputs()) ->appendChild($this->renderChildren()); } + + /** + * Append a control to the form. + * + * This method behaves like @{method:appendChild}, but it only takes + * controls. It will propagate some information from the form to the + * control to simplify rendering. + * + * @param AphrontFormControl Control to append. + * @return this + */ + public function appendControl(AphrontFormControl $control) { + $this->controls[] = $control; + return $this->appendChild($control); + } + + public function render() { require_celerity_resource('phui-form-view-css'); + foreach ($this->controls as $control) { + $control->setUser($this->getUser()); + } + $layout = $this->buildLayoutView(); if (!$this->user) { throw new Exception(pht('You must pass the user to AphrontFormView.')); } $sigils = $this->sigils; if ($this->workflow) { $sigils[] = 'workflow'; } return phabricator_form( $this->user, array( 'class' => $this->shaded ? 'phui-form-shaded' : null, 'action' => $this->action, 'method' => $this->method, 'enctype' => $this->encType, 'sigil' => $sigils ? implode(' ', $sigils) : null, 'meta' => $this->metadata, 'id' => $this->id, ), $layout->render()); } private function renderDataInputs() { $inputs = array(); foreach ($this->data as $key => $value) { if ($value === null) { continue; } $inputs[] = phutil_tag( 'input', array( 'type' => 'hidden', 'name' => $key, 'value' => $value, )); } return $inputs; } } diff --git a/src/view/form/control/AphrontFormTokenizerControl.php b/src/view/form/control/AphrontFormTokenizerControl.php index 24409293f5..5083650a76 100644 --- a/src/view/form/control/AphrontFormTokenizerControl.php +++ b/src/view/form/control/AphrontFormTokenizerControl.php @@ -1,85 +1,115 @@ datasource = $datasource; return $this; } public function setDisableBehavior($disable) { $this->disableBehavior = $disable; return $this; } protected function getCustomControlClass() { return 'aphront-form-control-tokenizer'; } public function setLimit($limit) { $this->limit = $limit; return $this; } public function setPlaceholder($placeholder) { $this->placeholder = $placeholder; return $this; } protected function renderInput() { $name = $this->getName(); $values = nonempty($this->getValue(), array()); - assert_instances_of($values, 'PhabricatorObjectHandle'); + // Values may either be handles (which are now legacy/deprecated) or + // strings. Load handles for any PHIDs. + $load = array(); + $handles = array(); + $select = array(); + foreach ($values as $value) { + if ($value instanceof PhabricatorObjectHandle) { + $handles[$value->getPHID()] = $value; + $select[] = $value->getPHID(); + } else { + $load[] = $value; + $select[] = $value; + } + } + + // TODO: Once this code path simplifies, move this prefetch to setValue() + // so we can bulk load across multiple controls. + + if ($load) { + $viewer = $this->getUser(); + if (!$viewer) { + // TODO: Clean this up when handles go away. + throw new Exception( + pht('Call setUser() before rendering tokenizer string values.')); + } + $loaded_handles = $viewer->loadHandles($load); + $handles = $handles + iterator_to_array($loaded_handles); + } + + // Reorder the list into input order. + $handles = array_select_keys($handles, $select); if ($this->getID()) { $id = $this->getID(); } else { $id = celerity_generate_unique_node_id(); } $placeholder = null; if (!strlen($this->placeholder)) { if ($this->datasource) { $placeholder = $this->datasource->getPlaceholderText(); } } else { $placeholder = $this->placeholder; } $template = new AphrontTokenizerTemplateView(); $template->setName($name); $template->setID($id); - $template->setValue($values); + $template->setValue($handles); $username = null; if ($this->user) { $username = $this->user->getUsername(); } $datasource_uri = null; if ($this->datasource) { $datasource_uri = $this->datasource->getDatasourceURI(); } if (!$this->disableBehavior) { Javelin::initBehavior('aphront-basic-tokenizer', array( 'id' => $id, 'src' => $datasource_uri, - 'value' => mpull($values, 'getFullName', 'getPHID'), - 'icons' => mpull($values, 'getIcon', 'getPHID'), + 'value' => mpull($handles, 'getFullName', 'getPHID'), + 'icons' => mpull($handles, 'getIcon', 'getPHID'), 'limit' => $this->limit, 'username' => $username, 'placeholder' => $placeholder, )); } return $template->render(); } }