private function buildResults() { $results = array(); $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); foreach ($priority_map as $value => $name) { $results[$value] = id(new PhabricatorTypeaheadResult())->setIcon(ManiphestTaskPriority::getTaskPriorityIcon($value))->setPHID($value)->setName($name); } return $results; }
public function getEditorValue(PhabricatorUser $viewer, $value) { $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); $value_map = array(); foreach ($value as $priority) { $value_map[$priority] = idx($priority_map, $priority, $priority); } return $value_map; }
public function render() { $handles = $this->handles; require_celerity_resource('maniphest-task-summary-css'); $list = new PHUIObjectItemListView(); if ($this->noDataString) { $list->setNoDataString($this->noDataString); } else { $list->setNoDataString(pht('No tasks.')); } $status_map = ManiphestTaskStatus::getTaskStatusMap(); $color_map = ManiphestTaskPriority::getColorMap(); $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); if ($this->showBatchControls) { Javelin::initBehavior('maniphest-list-editor'); } foreach ($this->tasks as $task) { $item = id(new PHUIObjectItemView())->setUser($this->getUser())->setObject($task)->setObjectName('T' . $task->getID())->setHeader($task->getTitle())->setHref('/T' . $task->getID()); if ($task->getOwnerPHID()) { $owner = $handles[$task->getOwnerPHID()]; $item->addByline(pht('Assigned: %s', $owner->renderLink())); } $status = $task->getStatus(); $pri = idx($priority_map, $task->getPriority()); $status_name = idx($status_map, $task->getStatus()); $tooltip = pht('%s, %s', $status_name, $pri); $icon = ManiphestTaskStatus::getStatusIcon($task->getStatus()); $color = idx($color_map, $task->getPriority(), 'grey'); if ($task->isClosed()) { $item->setDisabled(true); $color = 'grey'; } $item->setStatusIcon($icon . ' ' . $color, $tooltip); $item->addIcon('none', phabricator_datetime($task->getDateModified(), $this->getUser())); if ($this->showSubpriorityControls) { $item->setGrippable(true); } if ($this->showSubpriorityControls || $this->showBatchControls) { $item->addSigil('maniphest-task'); } $project_handles = array_select_keys($handles, array_reverse($task->getProjectPHIDs())); $item->addAttribute(id(new PHUIHandleTagListView())->setLimit(4)->setNoDataString(pht('No Projects'))->setSlim(true)->setHandles($project_handles)); $item->setMetadata(array('taskID' => $task->getID())); if ($this->showBatchControls) { $href = new PhutilURI('/maniphest/task/edit/' . $task->getID() . '/'); if (!$this->showSubpriorityControls) { $href->setQueryParam('ungrippable', 'true'); } $item->addAction(id(new PHUIListItemView())->setIcon('fa-pencil')->addSigil('maniphest-edit-task')->setHref($href)); } $list->addItem($item); } return $list; }
public function loadResults() { $viewer = $this->getViewer(); $raw_query = $this->getRawQuery(); $results = array(); $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); foreach ($priority_map as $value => $name) { // NOTE: $value is not a PHID but is unique. This'll work. $results[] = id(new PhabricatorTypeaheadResult())->setPHID($value)->setName($name); } return $results; }
public function processRequest() { $this->requireApplicationCapability(ManiphestBulkEditCapability::CAPABILITY); $request = $this->getRequest(); $user = $request->getUser(); $task_ids = $request->getArr('batch'); $tasks = id(new ManiphestTaskQuery())->setViewer($user)->withIDs($task_ids)->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->execute(); $actions = $request->getStr('actions'); if ($actions) { $actions = json_decode($actions, true); } if ($request->isFormPost() && is_array($actions)) { foreach ($tasks as $task) { $field_list = PhabricatorCustomField::getObjectFields($task, PhabricatorCustomField::ROLE_EDIT); $field_list->readFieldsFromStorage($task); $xactions = $this->buildTransactions($actions, $task); if ($xactions) { // TODO: Set content source to "batch edit". $editor = id(new ManiphestTransactionEditor())->setActor($user)->setContentSourceFromRequest($request)->setContinueOnNoEffect(true)->setContinueOnMissingFields(true)->applyTransactions($task, $xactions); } } $task_ids = implode(',', mpull($tasks, 'getID')); return id(new AphrontRedirectResponse())->setURI('/maniphest/?ids=' . $task_ids); } $handles = ManiphestTaskListView::loadTaskHandles($user, $tasks); $list = new ManiphestTaskListView(); $list->setTasks($tasks); $list->setUser($user); $list->setHandles($handles); $template = new AphrontTokenizerTemplateView(); $template = $template->render(); $projects_source = new PhabricatorProjectDatasource(); $mailable_source = new PhabricatorMetaMTAMailableDatasource(); $owner_source = new PhabricatorTypeaheadOwnerDatasource(); require_celerity_resource('maniphest-batch-editor'); Javelin::initBehavior('maniphest-batch-editor', array('root' => 'maniphest-batch-edit-form', 'tokenizerTemplate' => $template, 'sources' => array('project' => array('src' => $projects_source->getDatasourceURI(), 'placeholder' => $projects_source->getPlaceholderText()), 'owner' => array('src' => $owner_source->getDatasourceURI(), 'placeholder' => $owner_source->getPlaceholderText(), 'limit' => 1), 'cc' => array('src' => $mailable_source->getDatasourceURI(), 'placeholder' => $mailable_source->getPlaceholderText())), 'input' => 'batch-form-actions', 'priorityMap' => ManiphestTaskPriority::getTaskPriorityMap(), 'statusMap' => ManiphestTaskStatus::getTaskStatusMap())); $form = new AphrontFormView(); $form->setUser($user); $form->setID('maniphest-batch-edit-form'); foreach ($tasks as $task) { $form->appendChild(phutil_tag('input', array('type' => 'hidden', 'name' => 'batch[]', 'value' => $task->getID()))); } $form->appendChild(phutil_tag('input', array('type' => 'hidden', 'name' => 'actions', 'id' => 'batch-form-actions'))); $form->appendChild(phutil_tag('p', array(), pht('These tasks will be edited:'))); $form->appendChild($list); $form->appendChild(id(new AphrontFormInsetView())->setTitle('Actions')->setRightButton(javelin_tag('a', array('href' => '#', 'class' => 'button green', 'sigil' => 'add-action', 'mustcapture' => true), pht('Add Another Action')))->setContent(javelin_tag('table', array('sigil' => 'maniphest-batch-actions', 'class' => 'maniphest-batch-actions-table'), '')))->appendChild(id(new AphrontFormSubmitControl())->setValue(pht('Update Tasks'))->addCancelButton('/maniphest/')); $title = pht('Batch Editor'); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($title); $form_box = id(new PHUIObjectBoxView())->setHeaderText(pht('Batch Edit Tasks'))->setForm($form); return $this->buildApplicationPage(array($crumbs, $form_box), array('title' => $title, 'device' => false)); }
private function buildResults() { $results = array(); $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); foreach ($priority_map as $value => $name) { $result = id(new PhabricatorTypeaheadResult())->setIcon(ManiphestTaskPriority::getTaskPriorityIcon($value))->setPHID($value)->setName($name)->addAttribute(pht('Priority')); if (ManiphestTaskPriority::isDisabledPriority($value)) { $result->setClosed(pht('Disabled')); } $results[$value] = $result; } return $results; }
public function getCommandDescription() { $names = ManiphestTaskPriority::getTaskPriorityMap(); $keywords = ManiphestTaskPriority::getTaskPriorityKeywordsMap(); $table = array(); $table[] = '| ' . pht('Priority') . ' | ' . pht('Keywords'); $table[] = '|---|---|'; foreach ($keywords as $priority => $words) { $words = implode(', ', $words); $table[] = '| ' . $names[$priority] . ' | ' . $words; } $table = implode("\n", $table); return pht("To change the priority of a task, specify the desired priority, like " . "`%s`. This table shows the configured names for priority levels." . "\n\n%s\n\n" . "If you specify an invalid priority, the command is ignored. This " . "command has no effect if you do not specify a priority.", '!priority high', $table); }
/** * @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 $tasks, array $handles, PhabricatorUser $user) { $sheet = $workbook->setActiveSheetIndex(0); $sheet->setTitle(pht('Tasks')); $widths = array(null, 15, null, 10, 15, 15, 60, 30, 20, 100); 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('ID'), pht('Owner'), pht('Status'), pht('Priority'), pht('Date Created'), pht('Date Updated'), pht('Deadline'), pht('Title'), pht('Projects'), pht('Description')); $is_date = array(false, false, false, false, true, true, true, false, false, false); $header_format = array('font' => array('bold' => true)); foreach ($tasks as $task) { $task_owner = null; if ($task->getOwnerPHID()) { $task_owner = $handles[$task->getOwnerPHID()]->getName(); } $projects = array(); foreach ($task->getProjectPHIDs() as $phid) { $projects[] = $handles[$phid]->getName(); } $projects = implode(', ', $projects); $custom_fields = PhabricatorCustomField::getObjectFields($task, PhabricatorCustomField::ROLE_VIEW); $custom_fields->setViewer($user)->readFieldsFromStorage($task); $fields = $custom_fields->getFields(); $rows[] = array('T' . $task->getID(), $task_owner, idx($status_map, $task->getStatus(), '?'), idx($pri_map, $task->getPriority(), '?'), $this->computeExcelDate($task->getDateCreated()), $this->computeExcelDate($task->getDateModified()), $this->computeExcelDate($fields['std:maniphest:Deadline']->getValueForStorage()), $task->getTitle(), $projects, id(new PhutilUTF8StringTruncator())->setMaximumBytes(512)->truncateString($task->getDescription())); } 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); } if ($is_date[$col]) { $code = PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD2; $sheet->getStyle($cell_name)->getNumberFormat()->setFormatCode($code); } else { $cell->setDataType(PHPExcel_Cell_DataType::TYPE_STRING); } } } }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $task_ids = $request->getArr('batch'); $tasks = id(new ManiphestTask())->loadAllWhere('id IN (%Ld)', $task_ids); $actions = $request->getStr('actions'); if ($actions) { $actions = json_decode($actions, true); } if ($request->isFormPost() && is_array($actions)) { foreach ($tasks as $task) { $xactions = $this->buildTransactions($actions, $task); if ($xactions) { $editor = new ManiphestTransactionEditor(); $editor->applyTransactions($task, $xactions); } } $task_ids = implode(',', mpull($tasks, 'getID')); return id(new AphrontRedirectResponse())->setURI('/maniphest/view/custom/?s=oc&tasks=' . $task_ids); } $panel = new AphrontPanelView(); $panel->setHeader('Maniphest Batch Editor'); $handle_phids = mpull($tasks, 'getOwnerPHID'); $handles = id(new PhabricatorObjectHandleData($handle_phids))->loadHandles(); $list = new ManiphestTaskListView(); $list->setTasks($tasks); $list->setUser($user); $list->setHandles($handles); $template = new AphrontTokenizerTemplateView(); $template = $template->render(); require_celerity_resource('maniphest-batch-editor'); Javelin::initBehavior('maniphest-batch-editor', array('root' => 'maniphest-batch-edit-form', 'tokenizerTemplate' => $template, 'sources' => array('project' => array('src' => '/typeahead/common/projects/', 'placeholder' => 'Type a project name...'), 'owner' => array('src' => '/typeahead/common/searchowner/', 'placeholder' => 'Type a user name...', 'limit' => 1)), 'input' => 'batch-form-actions', 'priorityMap' => ManiphestTaskPriority::getTaskPriorityMap(), 'statusMap' => ManiphestTaskStatus::getTaskStatusMap())); $form = new AphrontFormView(); $form->setUser($user); $form->setID('maniphest-batch-edit-form'); foreach ($tasks as $task) { $form->appendChild(phutil_render_tag('input', array('type' => 'hidden', 'name' => 'batch[]', 'value' => $task->getID()), null)); } $form->appendChild(phutil_render_tag('input', array('type' => 'hidden', 'name' => 'actions', 'id' => 'batch-form-actions'), null)); $form->appendChild('<p>These tasks will be edited:</p>'); $form->appendChild($list); $form->appendChild(id(new AphrontFormInsetView())->setTitle('Actions')->setRightButton(javelin_render_tag('a', array('href' => '#', 'class' => 'button green', 'sigil' => 'add-action', 'mustcapture' => true), 'Add Another Action'))->setContent(javelin_render_tag('table', array('sigil' => 'maniphest-batch-actions', 'class' => 'maniphest-batch-actions-table'), '')))->appendChild(id(new AphrontFormSubmitControl())->setValue('Update Tasks')->addCancelButton('/maniphest/', 'Done')); $panel->appendChild($form); return $this->buildStandardPageResponse($panel, array('title' => 'Batch Editor')); }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $response_type = $request->getStr('responseType', 'task'); $order = $request->getStr('order', PhabricatorProjectColumn::DEFAULT_ORDER); $can_edit_assign = $this->hasApplicationCapability(ManiphestEditAssignCapability::CAPABILITY); $can_edit_policies = $this->hasApplicationCapability(ManiphestEditPoliciesCapability::CAPABILITY); $can_edit_priority = $this->hasApplicationCapability(ManiphestEditPriorityCapability::CAPABILITY); $can_edit_projects = $this->hasApplicationCapability(ManiphestEditProjectsCapability::CAPABILITY); $can_edit_status = $this->hasApplicationCapability(ManiphestEditStatusCapability::CAPABILITY); $parent_task = null; $template_id = null; if ($this->id) { $task = id(new ManiphestTaskQuery())->setViewer($user)->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->withIDs(array($this->id))->executeOne(); if (!$task) { return new Aphront404Response(); } } else { $task = ManiphestTask::initializeNewTask($user); // We currently do not allow you to set the task status when creating // a new task, although now that statuses are custom it might make // sense. $can_edit_status = false; // These allow task creation with defaults. if (!$request->isFormPost()) { $task->setTitle($request->getStr('title')); if ($can_edit_projects) { $projects = $request->getStr('projects'); if ($projects) { $tokens = $request->getStrList('projects'); $type_project = PhabricatorProjectProjectPHIDType::TYPECONST; foreach ($tokens as $key => $token) { if (phid_get_type($token) == $type_project) { // If this is formatted like a PHID, leave it as-is. continue; } if (preg_match('/^#/', $token)) { // If this already has a "#", leave it as-is. continue; } // Add a "#" prefix. $tokens[$key] = '#' . $token; } $default_projects = id(new PhabricatorObjectQuery())->setViewer($user)->withNames($tokens)->execute(); $default_projects = mpull($default_projects, 'getPHID'); if ($default_projects) { $task->attachProjectPHIDs($default_projects); } } } if ($can_edit_priority) { $priority = $request->getInt('priority'); if ($priority !== null) { $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); if (isset($priority_map[$priority])) { $task->setPriority($priority); } } } $task->setDescription($request->getStr('description')); if ($can_edit_assign) { $assign = $request->getStr('assign'); if (strlen($assign)) { $assign_user = id(new PhabricatorPeopleQuery())->setViewer($user)->withUsernames(array($assign))->executeOne(); if (!$assign_user) { $assign_user = id(new PhabricatorPeopleQuery())->setViewer($user)->withPHIDs(array($assign))->executeOne(); } if ($assign_user) { $task->setOwnerPHID($assign_user->getPHID()); } } } } $template_id = $request->getInt('template'); // You can only have a parent task if you're creating a new task. $parent_id = $request->getInt('parent'); if ($parent_id) { $parent_task = id(new ManiphestTaskQuery())->setViewer($user)->withIDs(array($parent_id))->executeOne(); if (!$template_id) { $template_id = $parent_id; } } } $errors = array(); $e_title = true; $field_list = PhabricatorCustomField::getObjectFields($task, PhabricatorCustomField::ROLE_EDIT); $field_list->setViewer($user); $field_list->readFieldsFromStorage($task); $aux_fields = $field_list->getFields(); if ($request->isFormPost()) { $changes = array(); $new_title = $request->getStr('title'); $new_desc = $request->getStr('description'); $new_status = $request->getStr('status'); if (!$task->getID()) { $workflow = 'create'; } else { $workflow = ''; } $changes[ManiphestTransaction::TYPE_TITLE] = $new_title; $changes[ManiphestTransaction::TYPE_DESCRIPTION] = $new_desc; if ($can_edit_status) { $changes[ManiphestTransaction::TYPE_STATUS] = $new_status; } else { if (!$task->getID()) { // Create an initial status transaction for the burndown chart. // TODO: We can probably remove this once Facts comes online. $changes[ManiphestTransaction::TYPE_STATUS] = $task->getStatus(); } } $owner_tokenizer = $request->getArr('assigned_to'); $owner_phid = reset($owner_tokenizer); if (!strlen($new_title)) { $e_title = pht('Required'); $errors[] = pht('Title is required.'); } $old_values = array(); foreach ($aux_fields as $aux_arr_key => $aux_field) { // TODO: This should be buildFieldTransactionsFromRequest() once we // switch to ApplicationTransactions properly. $aux_old_value = $aux_field->getOldValueForApplicationTransactions(); $aux_field->readValueFromRequest($request); $aux_new_value = $aux_field->getNewValueForApplicationTransactions(); // TODO: We're faking a call to the ApplicaitonTransaction validation // logic here. We need valid objects to pass, but they aren't used // in a meaningful way. For now, build User objects. Once the Maniphest // objects exist, this will switch over automatically. This is a big // hack but shouldn't be long for this world. $placeholder_editor = new PhabricatorUserProfileEditor(); $field_errors = $aux_field->validateApplicationTransactions($placeholder_editor, PhabricatorTransactions::TYPE_CUSTOMFIELD, array(id(new ManiphestTransaction())->setOldValue($aux_old_value)->setNewValue($aux_new_value))); foreach ($field_errors as $error) { $errors[] = $error->getMessage(); } $old_values[$aux_field->getFieldKey()] = $aux_old_value; } if ($errors) { $task->setTitle($new_title); $task->setDescription($new_desc); $task->setPriority($request->getInt('priority')); $task->setOwnerPHID($owner_phid); $task->setCCPHIDs($request->getArr('cc')); $task->attachProjectPHIDs($request->getArr('projects')); } else { if ($can_edit_priority) { $changes[ManiphestTransaction::TYPE_PRIORITY] = $request->getInt('priority'); } if ($can_edit_assign) { $changes[ManiphestTransaction::TYPE_OWNER] = $owner_phid; } $changes[ManiphestTransaction::TYPE_CCS] = $request->getArr('cc'); if ($can_edit_projects) { $projects = $request->getArr('projects'); $changes[ManiphestTransaction::TYPE_PROJECTS] = $projects; $column_phid = $request->getStr('columnPHID'); // allow for putting a task in a project column at creation -only- if (!$task->getID() && $column_phid && $projects) { $column = id(new PhabricatorProjectColumnQuery())->setViewer($user)->withProjectPHIDs($projects)->withPHIDs(array($column_phid))->executeOne(); if ($column) { $changes[ManiphestTransaction::TYPE_PROJECT_COLUMN] = array('new' => array('projectPHID' => $column->getProjectPHID(), 'columnPHIDs' => array($column_phid)), 'old' => array('projectPHID' => $column->getProjectPHID(), 'columnPHIDs' => array())); } } } if ($can_edit_policies) { $changes[PhabricatorTransactions::TYPE_VIEW_POLICY] = $request->getStr('viewPolicy'); $changes[PhabricatorTransactions::TYPE_EDIT_POLICY] = $request->getStr('editPolicy'); } $template = new ManiphestTransaction(); $transactions = array(); foreach ($changes as $type => $value) { $transaction = clone $template; $transaction->setTransactionType($type); if ($type == ManiphestTransaction::TYPE_PROJECT_COLUMN) { $transaction->setNewValue($value['new']); $transaction->setOldValue($value['old']); } else { if ($type == ManiphestTransaction::TYPE_PROJECTS) { // TODO: Gross. $project_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST; $transaction->setTransactionType(PhabricatorTransactions::TYPE_EDGE)->setMetadataValue('edge:type', $project_type)->setNewValue(array('=' => array_fuse($value))); } else { $transaction->setNewValue($value); } } $transactions[] = $transaction; } if ($aux_fields) { foreach ($aux_fields as $aux_field) { $transaction = clone $template; $transaction->setTransactionType(PhabricatorTransactions::TYPE_CUSTOMFIELD); $aux_key = $aux_field->getFieldKey(); $transaction->setMetadataValue('customfield:key', $aux_key); $old = idx($old_values, $aux_key); $new = $aux_field->getNewValueForApplicationTransactions(); $transaction->setOldValue($old); $transaction->setNewValue($new); $transactions[] = $transaction; } } if ($transactions) { $is_new = !$task->getID(); $event = new PhabricatorEvent(PhabricatorEventType::TYPE_MANIPHEST_WILLEDITTASK, array('task' => $task, 'new' => $is_new, 'transactions' => $transactions)); $event->setUser($user); $event->setAphrontRequest($request); PhutilEventEngine::dispatchEvent($event); $task = $event->getValue('task'); $transactions = $event->getValue('transactions'); $editor = id(new ManiphestTransactionEditor())->setActor($user)->setContentSourceFromRequest($request)->setContinueOnNoEffect(true)->applyTransactions($task, $transactions); $event = new PhabricatorEvent(PhabricatorEventType::TYPE_MANIPHEST_DIDEDITTASK, array('task' => $task, 'new' => $is_new, 'transactions' => $transactions)); $event->setUser($user); $event->setAphrontRequest($request); PhutilEventEngine::dispatchEvent($event); } if ($parent_task) { // TODO: This should be transactional now. id(new PhabricatorEdgeEditor())->addEdge($parent_task->getPHID(), PhabricatorEdgeConfig::TYPE_TASK_DEPENDS_ON_TASK, $task->getPHID())->save(); $workflow = $parent_task->getID(); } if ($request->isAjax()) { switch ($response_type) { case 'card': $owner = null; if ($task->getOwnerPHID()) { $owner = id(new PhabricatorHandleQuery())->setViewer($user)->withPHIDs(array($task->getOwnerPHID()))->executeOne(); } $tasks = id(new ProjectBoardTaskCard())->setViewer($user)->setTask($task)->setOwner($owner)->setCanEdit(true)->getItem(); $column = id(new PhabricatorProjectColumnQuery())->setViewer($user)->withPHIDs(array($request->getStr('columnPHID')))->executeOne(); if (!$column) { return new Aphront404Response(); } $positions = id(new PhabricatorProjectColumnPositionQuery())->setViewer($user)->withColumns(array($column))->execute(); $task_phids = mpull($positions, 'getObjectPHID'); $column_tasks = id(new ManiphestTaskQuery())->setViewer($user)->withPHIDs($task_phids)->execute(); if ($order == PhabricatorProjectColumn::ORDER_NATURAL) { // TODO: This is a little bit awkward, because PHP and JS use // slightly different sort order parameters to achieve the same // effect. It would be unify this a bit at some point. $sort_map = array(); foreach ($positions as $position) { $sort_map[$position->getObjectPHID()] = array(-$position->getSequence(), $position->getID()); } } else { $sort_map = mpull($column_tasks, 'getPrioritySortVector', 'getPHID'); } $data = array('sortMap' => $sort_map); break; case 'task': default: $tasks = $this->renderSingleTask($task); $data = array(); break; } return id(new AphrontAjaxResponse())->setContent(array('tasks' => $tasks, 'data' => $data)); } $redirect_uri = '/T' . $task->getID(); if ($workflow) { $redirect_uri .= '?workflow=' . $workflow; } return id(new AphrontRedirectResponse())->setURI($redirect_uri); } } else { if (!$task->getID()) { $task->setCCPHIDs(array($user->getPHID())); if ($template_id) { $template_task = id(new ManiphestTaskQuery())->setViewer($user)->withIDs(array($template_id))->executeOne(); if ($template_task) { $cc_phids = array_unique(array_merge($template_task->getCCPHIDs(), array($user->getPHID()))); $task->setCCPHIDs($cc_phids); $task->attachProjectPHIDs($template_task->getProjectPHIDs()); $task->setOwnerPHID($template_task->getOwnerPHID()); $task->setPriority($template_task->getPriority()); $task->setViewPolicy($template_task->getViewPolicy()); $task->setEditPolicy($template_task->getEditPolicy()); $template_fields = PhabricatorCustomField::getObjectFields($template_task, PhabricatorCustomField::ROLE_EDIT); $fields = $template_fields->getFields(); foreach ($fields as $key => $field) { if (!$field->shouldCopyWhenCreatingSimilarTask()) { unset($fields[$key]); } if (empty($aux_fields[$key])) { unset($fields[$key]); } } if ($fields) { id(new PhabricatorCustomFieldList($fields))->setViewer($user)->readFieldsFromStorage($template_task); foreach ($fields as $key => $field) { $aux_fields[$key]->setValueFromStorage($field->getValueForStorage()); } } } } } } $phids = array_merge(array($task->getOwnerPHID()), $task->getCCPHIDs(), $task->getProjectPHIDs()); if ($parent_task) { $phids[] = $parent_task->getPHID(); } $phids = array_filter($phids); $phids = array_unique($phids); $handles = $this->loadViewerHandles($phids); $error_view = null; if ($errors) { $error_view = new AphrontErrorView(); $error_view->setErrors($errors); } $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); if ($task->getOwnerPHID()) { $assigned_value = array($handles[$task->getOwnerPHID()]); } else { $assigned_value = array(); } if ($task->getCCPHIDs()) { $cc_value = array_select_keys($handles, $task->getCCPHIDs()); } else { $cc_value = array(); } if ($task->getProjectPHIDs()) { $projects_value = array_select_keys($handles, $task->getProjectPHIDs()); } else { $projects_value = array(); } $cancel_id = nonempty($task->getID(), $template_id); if ($cancel_id) { $cancel_uri = '/T' . $cancel_id; } else { $cancel_uri = '/maniphest/'; } if ($task->getID()) { $button_name = pht('Save Task'); $header_name = pht('Edit Task'); } else { if ($parent_task) { $cancel_uri = '/T' . $parent_task->getID(); $button_name = pht('Create Task'); $header_name = pht('Create New Subtask'); } else { $button_name = pht('Create Task'); $header_name = pht('Create New Task'); } } require_celerity_resource('maniphest-task-edit-css'); $project_tokenizer_id = celerity_generate_unique_node_id(); $form = new AphrontFormView(); $form->setUser($user)->addHiddenInput('template', $template_id)->addHiddenInput('responseType', $response_type)->addHiddenInput('order', $order)->addHiddenInput('ungrippable', $request->getStr('ungrippable'))->addHiddenInput('columnPHID', $request->getStr('columnPHID')); if ($parent_task) { $form->appendChild(id(new AphrontFormStaticControl())->setLabel(pht('Parent Task'))->setValue($handles[$parent_task->getPHID()]->getFullName()))->addHiddenInput('parent', $parent_task->getID()); } $form->appendChild(id(new AphrontFormTextAreaControl())->setLabel(pht('Title'))->setName('title')->setError($e_title)->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_SHORT)->setValue($task->getTitle())); if ($can_edit_status) { // See T4819. $status_map = ManiphestTaskStatus::getTaskStatusMap(); $dup_status = ManiphestTaskStatus::getDuplicateStatus(); if ($task->getStatus() != $dup_status) { unset($status_map[$dup_status]); } $form->appendChild(id(new AphrontFormSelectControl())->setLabel(pht('Status'))->setName('status')->setValue($task->getStatus())->setOptions($status_map)); } $policies = id(new PhabricatorPolicyQuery())->setViewer($user)->setObject($task)->execute(); if ($can_edit_assign) { $form->appendChild(id(new AphrontFormTokenizerControl())->setLabel(pht('Assigned To'))->setName('assigned_to')->setValue($assigned_value)->setUser($user)->setDatasource(new PhabricatorPeopleDatasource())->setLimit(1)); } $form->appendChild(id(new AphrontFormTokenizerControl())->setLabel(pht('CC'))->setName('cc')->setValue($cc_value)->setUser($user)->setDatasource(new PhabricatorMetaMTAMailableDatasource())); if ($can_edit_priority) { $form->appendChild(id(new AphrontFormSelectControl())->setLabel(pht('Priority'))->setName('priority')->setOptions($priority_map)->setValue($task->getPriority())); } if ($can_edit_policies) { $form->appendChild(id(new AphrontFormPolicyControl())->setUser($user)->setCapability(PhabricatorPolicyCapability::CAN_VIEW)->setPolicyObject($task)->setPolicies($policies)->setName('viewPolicy'))->appendChild(id(new AphrontFormPolicyControl())->setUser($user)->setCapability(PhabricatorPolicyCapability::CAN_EDIT)->setPolicyObject($task)->setPolicies($policies)->setName('editPolicy')); } if ($can_edit_projects) { $form->appendChild(id(new AphrontFormTokenizerControl())->setLabel(pht('Projects'))->setName('projects')->setValue($projects_value)->setID($project_tokenizer_id)->setCaption(javelin_tag('a', array('href' => '/project/create/', 'mustcapture' => true, 'sigil' => 'project-create'), pht('Create New Project')))->setDatasource(new PhabricatorProjectDatasource())); } $field_list->appendFieldsToForm($form); require_celerity_resource('aphront-error-view-css'); Javelin::initBehavior('project-create', array('tokenizerID' => $project_tokenizer_id)); $description_control = new PhabricatorRemarkupControl(); // "Upsell" creating tasks via email in create flows if the instance is // configured for this awesomeness. $email_create = PhabricatorEnv::getEnvConfig('metamta.maniphest.public-create-email'); if (!$task->getID() && $email_create) { $email_hint = pht('You can also create tasks by sending an email to: %s', phutil_tag('tt', array(), $email_create)); $description_control->setCaption($email_hint); } $description_control->setLabel(pht('Description'))->setName('description')->setID('description-textarea')->setValue($task->getDescription())->setUser($user); $form->appendChild($description_control); if ($request->isAjax()) { $dialog = id(new AphrontDialogView())->setUser($user)->setWidth(AphrontDialogView::WIDTH_FULL)->setTitle($header_name)->appendChild(array($error_view, $form->buildLayoutView()))->addCancelButton($cancel_uri)->addSubmitButton($button_name); return id(new AphrontDialogResponse())->setDialog($dialog); } $form->appendChild(id(new AphrontFormSubmitControl())->addCancelButton($cancel_uri)->setValue($button_name)); $form_box = id(new PHUIObjectBoxView())->setHeaderText($header_name)->setFormErrors($errors)->setForm($form); $preview = id(new PHUIRemarkupPreviewPanel())->setHeader(pht('Description Preview'))->setControlID('description-textarea')->setPreviewURI($this->getApplicationURI('task/descriptionpreview/')); if ($task->getID()) { $page_objects = array($task->getPHID()); } else { $page_objects = array(); } $crumbs = $this->buildApplicationCrumbs(); if ($task->getID()) { $crumbs->addTextCrumb('T' . $task->getID(), '/T' . $task->getID()); } $crumbs->addTextCrumb($header_name); return $this->buildApplicationPage(array($crumbs, $form_box, $preview), array('title' => $header_name, 'pageObjects' => $page_objects)); }
public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); $this->requireApplicationCapability(ManiphestBulkEditCapability::CAPABILITY); $project = null; $board_id = $request->getInt('board'); if ($board_id) { $project = id(new PhabricatorProjectQuery())->setViewer($viewer)->withIDs(array($board_id))->executeOne(); if (!$project) { return new Aphront404Response(); } } $task_ids = $request->getArr('batch'); if (!$task_ids) { $task_ids = $request->getStrList('batch'); } if (!$task_ids) { throw new Exception(pht('No tasks are selected.')); } $tasks = id(new ManiphestTaskQuery())->setViewer($viewer)->withIDs($task_ids)->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->needSubscriberPHIDs(true)->needProjectPHIDs(true)->execute(); if (!$tasks) { throw new Exception(pht("You don't have permission to edit any of the selected tasks.")); } if ($project) { $cancel_uri = '/project/board/' . $project->getID() . '/'; $redirect_uri = $cancel_uri; } else { $cancel_uri = '/maniphest/'; $redirect_uri = '/maniphest/?ids=' . implode(',', mpull($tasks, 'getID')); } $actions = $request->getStr('actions'); if ($actions) { $actions = phutil_json_decode($actions); } if ($request->isFormPost() && $actions) { $job = PhabricatorWorkerBulkJob::initializeNewJob($viewer, new ManiphestTaskEditBulkJobType(), array('taskPHIDs' => mpull($tasks, 'getPHID'), 'actions' => $actions, 'cancelURI' => $cancel_uri, 'doneURI' => $redirect_uri)); $type_status = PhabricatorWorkerBulkJobTransaction::TYPE_STATUS; $xactions = array(); $xactions[] = id(new PhabricatorWorkerBulkJobTransaction())->setTransactionType($type_status)->setNewValue(PhabricatorWorkerBulkJob::STATUS_CONFIRM); $editor = id(new PhabricatorWorkerBulkJobEditor())->setActor($viewer)->setContentSourceFromRequest($request)->setContinueOnMissingFields(true)->applyTransactions($job, $xactions); return id(new AphrontRedirectResponse())->setURI($job->getMonitorURI()); } $handles = ManiphestTaskListView::loadTaskHandles($viewer, $tasks); $list = new ManiphestTaskListView(); $list->setTasks($tasks); $list->setUser($viewer); $list->setHandles($handles); $template = new AphrontTokenizerTemplateView(); $template = $template->render(); $projects_source = new PhabricatorProjectDatasource(); $mailable_source = new PhabricatorMetaMTAMailableDatasource(); $mailable_source->setViewer($viewer); $owner_source = new ManiphestAssigneeDatasource(); $owner_source->setViewer($viewer); $spaces_source = id(new PhabricatorSpacesNamespaceDatasource())->setViewer($viewer); require_celerity_resource('maniphest-batch-editor'); Javelin::initBehavior('maniphest-batch-editor', array('root' => 'maniphest-batch-edit-form', 'tokenizerTemplate' => $template, 'sources' => array('project' => array('src' => $projects_source->getDatasourceURI(), 'placeholder' => $projects_source->getPlaceholderText(), 'browseURI' => $projects_source->getBrowseURI()), 'owner' => array('src' => $owner_source->getDatasourceURI(), 'placeholder' => $owner_source->getPlaceholderText(), 'browseURI' => $owner_source->getBrowseURI(), 'limit' => 1), 'cc' => array('src' => $mailable_source->getDatasourceURI(), 'placeholder' => $mailable_source->getPlaceholderText(), 'browseURI' => $mailable_source->getBrowseURI()), 'spaces' => array('src' => $spaces_source->getDatasourceURI(), 'placeholder' => $spaces_source->getPlaceholderText(), 'browseURI' => $spaces_source->getBrowseURI(), 'limit' => 1)), 'input' => 'batch-form-actions', 'priorityMap' => ManiphestTaskPriority::getTaskPriorityMap(), 'statusMap' => ManiphestTaskStatus::getTaskStatusMap())); $form = id(new AphrontFormView())->setUser($viewer)->addHiddenInput('board', $board_id)->setID('maniphest-batch-edit-form'); foreach ($tasks as $task) { $form->appendChild(phutil_tag('input', array('type' => 'hidden', 'name' => 'batch[]', 'value' => $task->getID()))); } $form->appendChild(phutil_tag('input', array('type' => 'hidden', 'name' => 'actions', 'id' => 'batch-form-actions'))); $form->appendChild(id(new PHUIFormInsetView())->setTitle(pht('Actions'))->setRightButton(javelin_tag('a', array('href' => '#', 'class' => 'button green', 'sigil' => 'add-action', 'mustcapture' => true), pht('Add Another Action')))->setContent(javelin_tag('table', array('sigil' => 'maniphest-batch-actions', 'class' => 'maniphest-batch-actions-table'), '')))->appendChild(id(new AphrontFormSubmitControl())->setValue(pht('Update Tasks'))->addCancelButton($cancel_uri)); $title = pht('Batch Editor'); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($title); $task_box = id(new PHUIObjectBoxView())->setHeaderText(pht('Selected Tasks'))->setObjectList($list); $form_box = id(new PHUIObjectBoxView())->setHeaderText(pht('Batch Editor'))->setForm($form); return $this->buildApplicationPage(array($crumbs, $task_box, $form_box), array('title' => $title)); }
public function buildWorkbook(PHPExcel $workbook, array $tasks, array $handles, PhabricatorUser $user) { $sheet = $workbook->setActiveSheetIndex(0); $sheet->setTitle(pht('Tasks')); // Header Cell // title => the displayed header title in the spreadsheet, in row 0 // width => initial width in pixels for the column, null leaves unspecified // celltype => which format the column data should be set as, default is STRING // can be null if it's a date field // isDate => there is no date format in the PHPExcel_Cell_DataType, so this is needed // cftype => the custom field data type, only specified for custom field headers $colHeaders = array(array('title' => pht('ID'), 'width' => null, 'celltype' => PHPExcel_Cell_DataType::TYPE_STRING, 'isDate' => false), array('title' => pht('Owner'), 'width' => 15, 'celltype' => PHPExcel_Cell_DataType::TYPE_STRING, 'isDate' => false), array('title' => pht('Status'), 'width' => null, 'celltype' => PHPExcel_Cell_DataType::TYPE_STRING, 'isDate' => false), array('title' => pht('Priority'), 'width' => 10, 'celltype' => PHPExcel_Cell_DataType::TYPE_STRING, 'isDate' => false), array('title' => pht('Date Created'), 'width' => 15, 'celltype' => null, 'isDate' => true), array('title' => pht('Date Updated'), 'width' => 15, 'celltype' => null, 'isDate' => true), array('title' => pht('Title'), 'width' => 60, 'celltype' => PHPExcel_Cell_DataType::TYPE_STRING, 'isDate' => false), array('title' => pht('Projects'), 'width' => 20, 'celltype' => PHPExcel_Cell_DataType::TYPE_STRING, 'isDate' => false), array('title' => pht('Columns'), 'width' => 20, 'celltype' => PHPExcel_Cell_DataType::TYPE_STRING, 'isDate' => false), array('title' => pht('URI'), 'width' => 30, 'celltype' => PHPExcel_Cell_DataType::TYPE_STRING, 'isDate' => false)); // Create the custom fields from their configured definition and extract header cell details $customFields = id(new ManiphestConfiguredCustomField())->createFields(null); $customFieldsHeaderMap = array(); foreach ($customFields as $customField) { // Using the proxy I think is needed due to using ManiphestConfiguredCustomField.createFields // That seems to be wrapping the PhabricatorStandardCustomField, but doesn't proxy/delegate the // getFieldType() method which is needed here. $fieldName = $customField->getProxy()->getFieldName(); $fieldType = $customField->getProxy()->getFieldType(); $isDateField = $fieldType == 'date'; $cellType = PHPExcel_Cell_DataType::TYPE_STRING; if ($fieldType == 'int') { $cellType = PHPExcel_Cell_DataType::TYPE_NUMERIC; } $customFieldHeader = array('title' => $fieldName, 'width' => null, 'celltype' => $cellType, 'isDate' => $isDateField, 'cftype' => $fieldType); $customFieldsHeaderMap[$fieldName] = $customFieldHeader; $colHeaders[] = $customFieldHeader; } $colHeaders[] = array('title' => pht('Description'), 'width' => 100, 'celltype' => PHPExcel_Cell_DataType::TYPE_STRING, 'isDate' => false); $status_map = ManiphestTaskStatus::getTaskStatusMap(); $pri_map = ManiphestTaskPriority::getTaskPriorityMap(); $header_format = array('font' => array('bold' => true)); $rows = array(); $headerRow = array(); foreach ($colHeaders as $colIdx => $column) { $headerRow[] = $column['title']; } $rows[] = $headerRow; $project_ids_used = array(); foreach ($tasks as $task) { foreach ($task->getProjectPHIDs() as $phid) { $project_ids_used[] = $phid; } } $project_ids_used = array_unique($project_ids_used); $ppositions = id(new PhabricatorProjectColumnPositionQuery())->setViewer($user)->withObjectPHIDs(mpull($tasks, 'getPHID'))->needColumns(true)->execute(); $ppositions = mpull($ppositions, null, 'getObjectPHID'); $task_phid_to_ppositions = array(); foreach ($tasks as $task) { $task_phid = $task->getPHID(); if (empty($ppositions[$task_phid])) { continue; } if (empty($task_phid_to_ppositions[$task_phid])) { $task_phid_to_ppositions[$task_phid] = array(); } $task_phid_to_ppositions[$task_phid][] = $ppositions[$task_phid]; } foreach ($tasks as $task) { $task_owner = null; if ($task->getOwnerPHID()) { $task_owner = $handles[$task->getOwnerPHID()]->getName(); } $projects = array(); $project_columns = array(); foreach ($task->getProjectPHIDs() as $phid) { $projects[] = $handles[$phid]->getName(); } $projects = implode(', ', $projects); $pcolumn_names = array(); $task_ppositions = $task_phid_to_ppositions[$task->getPHID()]; foreach ($task_ppositions as $task_position) { $pcolumn_names[] = $task_position->getColumn()->getDisplayName(); } $pcolumn_names = implode(', ', $pcolumn_names); $row = array('T' . $task->getID(), $task_owner, idx($status_map, $task->getStatus(), '?'), idx($pri_map, $task->getPriority(), '?'), $this->computeExcelDate($task->getDateCreated()), $this->computeExcelDate($task->getDateModified()), $task->getTitle(), $projects, $pcolumn_names, PhabricatorEnv::getProductionURI('/T' . $task->getID())); // Query for the custom fields for a specific maniphest task object $taskCustomFields = PhabricatorCustomField::getObjectFields($task, PhabricatorCustomField::ROLE_DEFAULT); $taskCustomFields->readFieldsFromStorage($task); $taskCustomFieldsMap = array(); foreach ($taskCustomFields->getFields() as $customField) { $fieldName = $customField->getFieldName(); $taskCustomFieldsMap[$fieldName] = $customField; } // We want to order the items from the task custom field object in the same order // which the custom field headers exist in the $colHeaders array // So loop over the header map, and pull the populated custom field from the populated map foreach ($customFieldsHeaderMap as $fieldName => $customFieldHeader) { $customField = $taskCustomFieldsMap[$fieldName]; if ($customField == null) { $row[] = null; continue; } $fieldValue = $customField->getProxy()->getFieldValue(); // option/select-style custom fields have values which are actually the identifier from json spec // lookup the display value to be used from the 'getOptions()' on the PhabricatorStandardCustomFieldSelect if ($fieldValue !== null && $customFieldHeader['cftype'] == 'select') { $options = $customField->getProxy()->getOptions(); $fieldValue = $options[$fieldValue]; } $row[] = $fieldValue; } $row[] = id(new PhutilUTF8StringTruncator())->setMaximumBytes(512)->truncateString($task->getDescription()); $rows[] = $row; } 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 the header row only apply the bold-style and width, but do not // apply the date-format/data-type since the values will always be string if ($row == 0) { $sheet->getStyle($cell_name)->applyFromArray($header_format); $width = $colHeaders[$col]['width']; if ($width !== null) { $sheet->getColumnDimension($this->col($col))->setWidth($width); } } else { $is_date = $colHeaders[$col]['isDate']; if ($is_date) { $code = PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD2; $sheet->getStyle($cell_name)->getNumberFormat()->setFormatCode($code); } else { $cellType = $colHeaders[$col]['celltype']; if ($cellType == null) { $cellType = PHPExcel_Cell_DataType::TYPE_STRING; } $cell->setDataType($cellType); } } } } }
protected function applyRequest(ManiphestTask $task, ConduitAPIRequest $request, $is_new) { $changes = array(); if ($is_new) { $task->setTitle((string) $request->getValue('title')); $task->setDescription((string) $request->getValue('description')); $changes[ManiphestTransaction::TYPE_STATUS] = ManiphestTaskStatus::getDefaultStatus(); $changes[PhabricatorTransactions::TYPE_SUBSCRIBERS] = array('+' => array($request->getUser()->getPHID())); } else { $comments = $request->getValue('comments'); if (!$is_new && $comments !== null) { $changes[PhabricatorTransactions::TYPE_COMMENT] = null; } $title = $request->getValue('title'); if ($title !== null) { $changes[ManiphestTransaction::TYPE_TITLE] = $title; } $desc = $request->getValue('description'); if ($desc !== null) { $changes[ManiphestTransaction::TYPE_DESCRIPTION] = $desc; } $status = $request->getValue('status'); if ($status !== null) { $valid_statuses = ManiphestTaskStatus::getTaskStatusMap(); if (!isset($valid_statuses[$status])) { throw id(new ConduitException('ERR-INVALID-PARAMETER'))->setErrorDescription(pht('Status set to invalid value.')); } $changes[ManiphestTransaction::TYPE_STATUS] = $status; } } $priority = $request->getValue('priority'); if ($priority !== null) { $valid_priorities = ManiphestTaskPriority::getTaskPriorityMap(); if (!isset($valid_priorities[$priority])) { throw id(new ConduitException('ERR-INVALID-PARAMETER'))->setErrorDescription(pht('Priority set to invalid value.')); } $changes[ManiphestTransaction::TYPE_PRIORITY] = $priority; } $owner_phid = $request->getValue('ownerPHID'); if ($owner_phid !== null) { $this->validatePHIDList(array($owner_phid), PhabricatorPeopleUserPHIDType::TYPECONST, 'ownerPHID'); $changes[ManiphestTransaction::TYPE_OWNER] = $owner_phid; } $ccs = $request->getValue('ccPHIDs'); if ($ccs !== null) { $changes[PhabricatorTransactions::TYPE_SUBSCRIBERS] = array('=' => array_fuse($ccs)); } $transactions = array(); $view_policy = $request->getValue('viewPolicy'); if ($view_policy !== null) { $transactions[] = id(new ManiphestTransaction())->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)->setNewValue($view_policy); } $edit_policy = $request->getValue('editPolicy'); if ($edit_policy !== null) { $transactions[] = id(new ManiphestTransaction())->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY)->setNewValue($edit_policy); } $project_phids = $request->getValue('projectPHIDs'); if ($project_phids !== null) { $this->validatePHIDList($project_phids, PhabricatorProjectProjectPHIDType::TYPECONST, 'projectPHIDS'); $project_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST; $transactions[] = id(new ManiphestTransaction())->setTransactionType(PhabricatorTransactions::TYPE_EDGE)->setMetadataValue('edge:type', $project_type)->setNewValue(array('=' => array_fuse($project_phids))); } $template = new ManiphestTransaction(); foreach ($changes as $type => $value) { $transaction = clone $template; $transaction->setTransactionType($type); if ($type == PhabricatorTransactions::TYPE_COMMENT) { $transaction->attachComment(id(new ManiphestTransactionComment())->setContent($comments)); } else { $transaction->setNewValue($value); } $transactions[] = $transaction; } $field_list = PhabricatorCustomField::getObjectFields($task, PhabricatorCustomField::ROLE_EDIT); $field_list->readFieldsFromStorage($task); $auxiliary = $request->getValue('auxiliary'); if ($auxiliary) { foreach ($field_list->getFields() as $key => $field) { if (!array_key_exists($key, $auxiliary)) { continue; } $transaction = clone $template; $transaction->setTransactionType(PhabricatorTransactions::TYPE_CUSTOMFIELD); $transaction->setMetadataValue('customfield:key', $key); $transaction->setOldValue($field->getOldValueForApplicationTransactions()); $transaction->setNewValue($auxiliary[$key]); $transactions[] = $transaction; } } if (!$transactions) { return; } $content_source = $request->newContentSource(); $editor = id(new ManiphestTransactionEditor())->setActor($request->getUser())->setContentSource($content_source)->setContinueOnNoEffect(true); if (!$is_new) { $editor->setContinueOnMissingFields(true); } $editor->applyTransactions($task, $transactions); // reload the task now that we've done all the fun stuff return id(new ManiphestTaskQuery())->setViewer($request->getUser())->withPHIDs(array($task->getPHID()))->needSubscriberPHIDs(true)->needProjectPHIDs(true)->executeOne(); }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); if ($request->isFormPost()) { // Redirect to GET so URIs can be copy/pasted. $task_ids = $request->getStr('set_tasks'); $task_ids = nonempty($task_ids, null); $search_text = $request->getStr('set_search'); $search_text = nonempty($search_text, null); $min_priority = $request->getInt('set_lpriority'); $min_priority = nonempty($min_priority, null); $max_priority = $request->getInt('set_hpriority'); $max_priority = nonempty($max_priority, null); $uri = $request->getRequestURI()->alter('users', $this->getArrToStrList('set_users'))->alter('projects', $this->getArrToStrList('set_projects'))->alter('xprojects', $this->getArrToStrList('set_xprojects'))->alter('owners', $this->getArrToStrList('set_owners'))->alter('authors', $this->getArrToStrList('set_authors'))->alter('lpriority', $min_priority)->alter('hpriority', $max_priority)->alter('tasks', $task_ids)->alter('search', $search_text); return id(new AphrontRedirectResponse())->setURI($uri); } $nav = $this->buildBaseSideNav(); $has_filter = array('action' => true, 'created' => true, 'subscribed' => true, 'triage' => true, 'projecttriage' => true, 'projectall' => true); $query = null; $key = $request->getStr('key'); if (!$key && !$this->view) { if ($this->getDefaultQuery()) { $key = $this->getDefaultQuery()->getQueryKey(); } } if ($key) { $query = id(new PhabricatorSearchQuery())->loadOneWhere('queryKey = %s', $key); } // If the user is running a saved query, load query parameters from that // query. Otherwise, build a new query object from the HTTP request. if ($query) { $nav->selectFilter('Q:' . $query->getQueryKey(), 'custom'); $this->view = 'custom'; } else { $this->view = $nav->selectFilter($this->view, 'action'); $query = $this->buildQueryFromRequest(); } // Execute the query. list($tasks, $handles, $total_count) = self::loadTasks($query); // Extract information we need to render the filters from the query. $search_text = $query->getParameter('fullTextSearch'); $user_phids = $query->getParameter('userPHIDs', array()); $task_ids = $query->getParameter('taskIDs', array()); $owner_phids = $query->getParameter('ownerPHIDs', array()); $author_phids = $query->getParameter('authorPHIDs', array()); $project_phids = $query->getParameter('projectPHIDs', array()); $exclude_project_phids = $query->getParameter('excludeProjectPHIDs', array()); $low_priority = $query->getParameter('lowPriority'); $high_priority = $query->getParameter('highPriority'); $page_size = $query->getParameter('limit'); $page = $query->getParameter('offset'); $q_status = $query->getParameter('status'); $q_group = $query->getParameter('group'); $q_order = $query->getParameter('order'); $form = id(new AphrontFormView())->setUser($user)->setAction($request->getRequestURI()->alter('key', null)->alter($this->getStatusRequestKey(), $this->getStatusRequestValue($q_status))->alter($this->getOrderRequestKey(), $this->getOrderRequestValue($q_order))->alter($this->getGroupRequestKey(), $this->getGroupRequestValue($q_group))); if (isset($has_filter[$this->view])) { $tokens = array(); foreach ($user_phids as $phid) { $tokens[$phid] = $handles[$phid]->getFullName(); } $form->appendChild(id(new AphrontFormTokenizerControl())->setDatasource('/typeahead/common/searchowner/')->setName('set_users')->setLabel('Users')->setValue($tokens)); } if ($this->view == 'custom') { $form->appendChild(id(new AphrontFormTextControl())->setName('set_search')->setLabel('Search')->setValue($search_text)); $form->appendChild(id(new AphrontFormTextControl())->setName('set_tasks')->setLabel('Task IDs')->setValue(join(',', $task_ids))); $tokens = array(); foreach ($owner_phids as $phid) { $tokens[$phid] = $handles[$phid]->getFullName(); } $form->appendChild(id(new AphrontFormTokenizerControl())->setDatasource('/typeahead/common/searchowner/')->setName('set_owners')->setLabel('Owners')->setValue($tokens)); $tokens = array(); foreach ($author_phids as $phid) { $tokens[$phid] = $handles[$phid]->getFullName(); } $form->appendChild(id(new AphrontFormTokenizerControl())->setDatasource('/typeahead/common/users/')->setName('set_authors')->setLabel('Authors')->setValue($tokens)); } $tokens = array(); foreach ($project_phids as $phid) { $tokens[$phid] = $handles[$phid]->getFullName(); } if ($this->view != 'projectall' && $this->view != 'projecttriage') { $form->appendChild(id(new AphrontFormTokenizerControl())->setDatasource('/typeahead/common/searchproject/')->setName('set_projects')->setLabel('Projects')->setValue($tokens)); } if ($this->view == 'custom') { $tokens = array(); foreach ($exclude_project_phids as $phid) { $tokens[$phid] = $handles[$phid]->getFullName(); } $form->appendChild(id(new AphrontFormTokenizerControl())->setDatasource('/typeahead/common/projects/')->setName('set_xprojects')->setLabel('Exclude Projects')->setValue($tokens)); $priority = ManiphestTaskPriority::getLowestPriority(); if ($low_priority) { $priority = $low_priority; } $form->appendChild(id(new AphrontFormSelectControl())->setLabel('Min Priority')->setName('set_lpriority')->setValue($priority)->setOptions(array_reverse(ManiphestTaskPriority::getTaskPriorityMap(), true))); $priority = ManiphestTaskPriority::getHighestPriority(); if ($high_priority) { $priority = $high_priority; } $form->appendChild(id(new AphrontFormSelectControl())->setLabel('Max Priority')->setName('set_hpriority')->setValue($priority)->setOptions(ManiphestTaskPriority::getTaskPriorityMap())); } $form->appendChild($this->renderStatusControl($q_status))->appendChild($this->renderGroupControl($q_group))->appendChild($this->renderOrderControl($q_order)); $submit = id(new AphrontFormSubmitControl())->setValue('Filter Tasks'); // Only show "Save..." for novel queries which have some kind of query // parameters set. if ($this->view === 'custom' && empty($key) && $request->getRequestURI()->getQueryParams()) { $submit->addCancelButton('/maniphest/custom/edit/?key=' . $query->getQueryKey(), 'Save Custom Query...'); } $form->appendChild($submit); $create_uri = new PhutilURI('/maniphest/task/create/'); if ($project_phids) { // If we have project filters selected, use them as defaults for task // creation. $create_uri->setQueryParam('projects', implode(';', $project_phids)); } $filter = new AphrontListFilterView(); $filter->addButton(phutil_render_tag('a', array('href' => (string) $create_uri, 'class' => 'green button'), 'Create New Task')); if (empty($key)) { $filter->appendChild($form); } $nav->appendChild($filter); $have_tasks = false; foreach ($tasks as $group => $list) { if (count($list)) { $have_tasks = true; break; } } require_celerity_resource('maniphest-task-summary-css'); $list_container = new AphrontNullView(); $list_container->appendChild('<div class="maniphest-list-container">'); if (!$have_tasks) { $list_container->appendChild('<h1 class="maniphest-task-group-header">' . 'No matching tasks.' . '</h1>'); } else { $pager = new AphrontPagerView(); $pager->setURI($request->getRequestURI(), 'offset'); $pager->setPageSize($page_size); $pager->setOffset($page); $pager->setCount($total_count); $cur = $pager->getOffset() + 1; $max = min($pager->getOffset() + $page_size, $total_count); $tot = $total_count; $cur = number_format($cur); $max = number_format($max); $tot = number_format($tot); $list_container->appendChild('<div class="maniphest-total-result-count">' . "Displaying tasks {$cur} - {$max} of {$tot}." . '</div>'); $selector = new AphrontNullView(); $group = $query->getParameter('group'); $order = $query->getParameter('order'); $is_draggable = $group == 'priority' || $group == 'none' && $order == 'priority'; $lists = new AphrontNullView(); $lists->appendChild('<div class="maniphest-group-container">'); foreach ($tasks as $group => $list) { $task_list = new ManiphestTaskListView(); $task_list->setShowBatchControls(true); if ($is_draggable) { $task_list->setShowSubpriorityControls(true); } $task_list->setUser($user); $task_list->setTasks($list); $task_list->setHandles($handles); $count = number_format(count($list)); $lists->appendChild(javelin_render_tag('h1', array('class' => 'maniphest-task-group-header', 'sigil' => 'task-group', 'meta' => array('priority' => head($list)->getPriority())), phutil_escape_html($group) . ' (' . $count . ')')); $lists->appendChild($task_list); } $lists->appendChild('</div>'); $selector->appendChild($lists); $selector->appendChild($this->renderBatchEditor($query)); $form_id = celerity_generate_unique_node_id(); $selector = phabricator_render_form($user, array('method' => 'POST', 'action' => '/maniphest/batch/', 'id' => $form_id), $selector->render()); $list_container->appendChild($selector); $list_container->appendChild($pager); Javelin::initBehavior('maniphest-subpriority-editor', array('root' => $form_id, 'uri' => '/maniphest/subpriority/')); } $list_container->appendChild('</div>'); $nav->appendChild($list_container); return $this->buildStandardPageResponse($nav, array('title' => 'Task List')); }
public function buildSearchForm(AphrontFormView $form, PhabricatorSavedQuery $saved) { $assigned_phids = $saved->getParameter('assignedPHIDs', array()); $author_phids = $saved->getParameter('authorPHIDs', array()); $all_project_phids = $saved->getParameter('allProjectPHIDs', array()); $any_project_phids = $saved->getParameter('anyProjectPHIDs', array()); $exclude_project_phids = $saved->getParameter('excludeProjectPHIDs', array()); $user_project_phids = $saved->getParameter('userProjectPHIDs', array()); $subscriber_phids = $saved->getParameter('subscriberPHIDs', array()); $all_phids = array_merge($assigned_phids, $author_phids, $all_project_phids, $any_project_phids, $exclude_project_phids, $user_project_phids, $subscriber_phids); if ($all_phids) { $handles = id(new PhabricatorHandleQuery())->setViewer($this->requireViewer())->withPHIDs($all_phids)->execute(); } else { $handles = array(); } $assigned_handles = array_select_keys($handles, $assigned_phids); $author_handles = array_select_keys($handles, $author_phids); $all_project_handles = array_select_keys($handles, $all_project_phids); $any_project_handles = array_select_keys($handles, $any_project_phids); $exclude_project_handles = array_select_keys($handles, $exclude_project_phids); $user_project_handles = array_select_keys($handles, $user_project_phids); $subscriber_handles = array_select_keys($handles, $subscriber_phids); $with_unassigned = $saved->getParameter('withUnassigned'); $with_no_projects = $saved->getParameter('withNoProject'); $statuses = $saved->getParameter('statuses', array()); $statuses = array_fuse($statuses); $status_control = id(new AphrontFormCheckboxControl())->setLabel(pht('Status')); foreach (ManiphestTaskStatus::getTaskStatusMap() as $status => $name) { $status_control->addCheckbox('statuses[]', $status, $name, isset($statuses[$status])); } $priorities = $saved->getParameter('priorities', array()); $priorities = array_fuse($priorities); $priority_control = id(new AphrontFormCheckboxControl())->setLabel(pht('Priority')); foreach (ManiphestTaskPriority::getTaskPriorityMap() as $pri => $name) { $priority_control->addCheckbox('priorities[]', $pri, $name, isset($priorities[$pri])); } $ids = $saved->getParameter('ids', array()); $builtin_orders = $this->getOrderOptions(); $custom_orders = $this->getCustomFieldOrderOptions(); $all_orders = $builtin_orders + $custom_orders; $form->appendChild(id(new AphrontFormTokenizerControl())->setDatasource(new PhabricatorPeopleDatasource())->setName('assigned')->setLabel(pht('Assigned To'))->setValue($assigned_handles))->appendChild(id(new AphrontFormCheckboxControl())->addCheckbox('withUnassigned', 1, pht('Show only unassigned tasks.'), $with_unassigned))->appendChild(id(new AphrontFormTokenizerControl())->setDatasource(new PhabricatorProjectDatasource())->setName('allProjects')->setLabel(pht('In All Projects'))->setValue($all_project_handles)); if (!$this->getIsBoardView()) { $form->appendChild(id(new AphrontFormCheckboxControl())->addCheckbox('withNoProject', 1, pht('Show only tasks with no projects.'), $with_no_projects)); } $form->appendChild(id(new AphrontFormTokenizerControl())->setDatasource(new PhabricatorProjectDatasource())->setName('anyProjects')->setLabel(pht('In Any Project'))->setValue($any_project_handles))->appendChild(id(new AphrontFormTokenizerControl())->setDatasource(new PhabricatorProjectDatasource())->setName('excludeProjects')->setLabel(pht('Not In Projects'))->setValue($exclude_project_handles))->appendChild(id(new AphrontFormTokenizerControl())->setDatasource(new PhabricatorPeopleDatasource())->setName('userProjects')->setLabel(pht('In Users\' Projects'))->setValue($user_project_handles))->appendChild(id(new AphrontFormTokenizerControl())->setDatasource(new PhabricatorPeopleDatasource())->setName('authors')->setLabel(pht('Authors'))->setValue($author_handles))->appendChild(id(new AphrontFormTokenizerControl())->setDatasource(new PhabricatorMetaMTAMailableDatasource())->setName('subscribers')->setLabel(pht('Subscribers'))->setValue($subscriber_handles))->appendChild($status_control)->appendChild($priority_control); if (!$this->getIsBoardView()) { $form->appendChild(id(new AphrontFormSelectControl())->setName('group')->setLabel(pht('Group By'))->setValue($saved->getParameter('group'))->setOptions($this->getGroupOptions()))->appendChild(id(new AphrontFormSelectControl())->setName('order')->setLabel(pht('Order By'))->setValue($saved->getParameter('order'))->setOptions($all_orders)); } $form->appendChild(id(new AphrontFormTextControl())->setName('fulltext')->setLabel(pht('Contains Words'))->setValue($saved->getParameter('fulltext')))->appendChild(id(new AphrontFormTextControl())->setName('ids')->setLabel(pht('Task IDs'))->setValue(implode(', ', $ids))); $this->appendCustomFieldsToForm($form, $saved); $this->buildDateRange($form, $saved, 'createdStart', pht('Created After'), 'createdEnd', pht('Created Before')); $this->buildDateRange($form, $saved, 'modifiedStart', pht('Updated After'), 'modifiedEnd', pht('Updated Before')); if (!$this->getIsBoardView()) { $form->appendChild(id(new AphrontFormTextControl())->setName('limit')->setLabel(pht('Page Size'))->setValue($saved->getParameter('limit', 100))); } }
public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); $id = $request->getURIData('id'); $e_title = null; $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); $task = id(new ManiphestTaskQuery())->setViewer($viewer)->withIDs(array($id))->needSubscriberPHIDs(true)->executeOne(); if (!$task) { return new Aphront404Response(); } $workflow = $request->getStr('workflow'); $parent_task = null; if ($workflow && is_numeric($workflow)) { $parent_task = id(new ManiphestTaskQuery())->setViewer($viewer)->withIDs(array($workflow))->executeOne(); } $field_list = PhabricatorCustomField::getObjectFields($task, PhabricatorCustomField::ROLE_VIEW); $field_list->setViewer($viewer)->readFieldsFromStorage($task); $e_commit = ManiphestTaskHasCommitEdgeType::EDGECONST; $e_dep_on = ManiphestTaskDependsOnTaskEdgeType::EDGECONST; $e_dep_by = ManiphestTaskDependedOnByTaskEdgeType::EDGECONST; $e_rev = ManiphestTaskHasRevisionEdgeType::EDGECONST; $e_mock = ManiphestTaskHasMockEdgeType::EDGECONST; $phid = $task->getPHID(); $query = id(new PhabricatorEdgeQuery())->withSourcePHIDs(array($phid))->withEdgeTypes(array($e_commit, $e_dep_on, $e_dep_by, $e_rev, $e_mock)); $edges = idx($query->execute(), $phid); $phids = array_fill_keys($query->getDestinationPHIDs(), true); if ($task->getOwnerPHID()) { $phids[$task->getOwnerPHID()] = true; } $phids[$task->getAuthorPHID()] = true; $attached = $task->getAttached(); foreach ($attached as $type => $list) { foreach ($list as $phid => $info) { $phids[$phid] = true; } } if ($parent_task) { $phids[$parent_task->getPHID()] = true; } $phids = array_keys($phids); $handles = $viewer->loadHandles($phids); $info_view = null; if ($parent_task) { $info_view = new PHUIInfoView(); $info_view->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $info_view->addButton(id(new PHUIButtonView())->setTag('a')->setHref('/maniphest/task/create/?parent=' . $parent_task->getID())->setText(pht('Create Another Subtask'))); $info_view->appendChild(hsprintf('Created a subtask of <strong>%s</strong>.', $handles->renderHandle($parent_task->getPHID()))); } else { if ($workflow == 'create') { $info_view = new PHUIInfoView(); $info_view->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $info_view->addButton(id(new PHUIButtonView())->setTag('a')->setHref('/maniphest/task/create/?template=' . $task->getID())->setText(pht('Similar Task'))); $info_view->addButton(id(new PHUIButtonView())->setTag('a')->setHref('/maniphest/task/create/')->setText(pht('Empty Task'))); $info_view->appendChild(pht('New task created. Create another?')); } } $engine = new PhabricatorMarkupEngine(); $engine->setViewer($viewer); $engine->setContextObject($task); $engine->addObject($task, ManiphestTask::MARKUP_FIELD_DESCRIPTION); $timeline = $this->buildTransactionTimeline($task, new ManiphestTransactionQuery(), $engine); $actions = $this->buildActionView($task); $monogram = $task->getMonogram(); $crumbs = $this->buildApplicationCrumbs()->addTextCrumb($monogram, '/' . $monogram); $header = $this->buildHeaderView($task); $properties = $this->buildPropertyView($task, $field_list, $edges, $actions, $handles); $description = $this->buildDescriptionView($task, $engine); $object_box = id(new PHUIObjectBoxView())->setHeader($header)->addPropertyList($properties); if ($description) { $object_box->addPropertyList($description); } $title = pht('%s %s', $monogram, $task->getTitle()); $comment_view = id(new ManiphestEditEngine())->setViewer($viewer)->buildEditEngineCommentView($task); $timeline->setQuoteRef($monogram); $comment_view->setTransactionTimeline($timeline); return $this->newPage()->setTitle($title)->setCrumbs($crumbs)->setPageObjectPHIDs(array($task->getPHID()))->appendChild(array($info_view, $object_box, $timeline, $comment_view)); }
public function renderOpenTasks() { $request = $this->getRequest(); $viewer = $request->getUser(); $query = id(new ManiphestTaskQuery())->setViewer($viewer)->withStatuses(ManiphestTaskStatus::getOpenStatusConstants()); switch ($this->view) { case 'project': $query->needProjectPHIDs(true); break; } $project_phid = $request->getStr('project'); $project_handle = null; if ($project_phid) { $phids = array($project_phid); $handles = $this->loadViewerHandles($phids); $project_handle = $handles[$project_phid]; $query->withEdgeLogicPHIDs(PhabricatorProjectObjectHasProjectEdgeType::EDGECONST, PhabricatorQueryConstraint::OPERATOR_OR, $phids); } $tasks = $query->execute(); $recently_closed = $this->loadRecentlyClosedTasks(); $date = phabricator_date(time(), $viewer); switch ($this->view) { case 'user': $result = mgroup($tasks, 'getOwnerPHID'); $leftover = idx($result, '', array()); unset($result['']); $result_closed = mgroup($recently_closed, 'getOwnerPHID'); $leftover_closed = idx($result_closed, '', array()); unset($result_closed['']); $base_link = '/maniphest/?assigned='; $leftover_name = phutil_tag('em', array(), pht('(Up For Grabs)')); $col_header = pht('User'); $header = pht('Open Tasks by User and Priority (%s)', $date); break; case 'project': $result = array(); $leftover = array(); foreach ($tasks as $task) { $phids = $task->getProjectPHIDs(); if ($phids) { foreach ($phids as $project_phid) { $result[$project_phid][] = $task; } } else { $leftover[] = $task; } } $result_closed = array(); $leftover_closed = array(); foreach ($recently_closed as $task) { $phids = $task->getProjectPHIDs(); if ($phids) { foreach ($phids as $project_phid) { $result_closed[$project_phid][] = $task; } } else { $leftover_closed[] = $task; } } $base_link = '/maniphest/?projects='; $leftover_name = phutil_tag('em', array(), pht('(No Project)')); $col_header = pht('Project'); $header = pht('Open Tasks by Project and Priority (%s)', $date); break; } $phids = array_keys($result); $handles = $this->loadViewerHandles($phids); $handles = msort($handles, 'getName'); $order = $request->getStr('order', 'name'); list($order, $reverse) = AphrontTableView::parseSort($order); require_celerity_resource('aphront-tooltip-css'); Javelin::initBehavior('phabricator-tooltips', array()); $rows = array(); $pri_total = array(); foreach (array_merge($handles, array(null)) as $handle) { if ($handle) { if ($project_handle && $project_handle->getPHID() == $handle->getPHID()) { // If filtering by, e.g., "bugs", don't show a "bugs" group. continue; } $tasks = idx($result, $handle->getPHID(), array()); $name = phutil_tag('a', array('href' => $base_link . $handle->getPHID()), $handle->getName()); $closed = idx($result_closed, $handle->getPHID(), array()); } else { $tasks = $leftover; $name = $leftover_name; $closed = $leftover_closed; } $taskv = $tasks; $tasks = mgroup($tasks, 'getPriority'); $row = array(); $row[] = $name; $total = 0; foreach (ManiphestTaskPriority::getTaskPriorityMap() as $pri => $label) { $n = count(idx($tasks, $pri, array())); if ($n == 0) { $row[] = '-'; } else { $row[] = number_format($n); } $total += $n; } $row[] = number_format($total); list($link, $oldest_all) = $this->renderOldest($taskv); $row[] = $link; $normal_or_better = array(); foreach ($taskv as $id => $task) { // TODO: This is sort of a hard-code for the default "normal" status. // When reports are more powerful, this should be made more general. if ($task->getPriority() < 50) { continue; } $normal_or_better[$id] = $task; } list($link, $oldest_pri) = $this->renderOldest($normal_or_better); $row[] = $link; if ($closed) { $task_ids = implode(',', mpull($closed, 'getID')); $row[] = phutil_tag('a', array('href' => '/maniphest/?ids=' . $task_ids, 'target' => '_blank'), number_format(count($closed))); } else { $row[] = '-'; } switch ($order) { case 'total': $row['sort'] = $total; break; case 'oldest-all': $row['sort'] = $oldest_all; break; case 'oldest-pri': $row['sort'] = $oldest_pri; break; case 'closed': $row['sort'] = count($closed); break; case 'name': default: $row['sort'] = $handle ? $handle->getName() : '~'; break; } $rows[] = $row; } $rows = isort($rows, 'sort'); foreach ($rows as $k => $row) { unset($rows[$k]['sort']); } if ($reverse) { $rows = array_reverse($rows); } $cname = array($col_header); $cclass = array('pri right wide'); $pri_map = ManiphestTaskPriority::getShortNameMap(); foreach ($pri_map as $pri => $label) { $cname[] = $label; $cclass[] = 'n'; } $cname[] = pht('Total'); $cclass[] = 'n'; $cname[] = javelin_tag('span', array('sigil' => 'has-tooltip', 'meta' => array('tip' => pht('Oldest open task.'), 'size' => 200)), pht('Oldest (All)')); $cclass[] = 'n'; $cname[] = javelin_tag('span', array('sigil' => 'has-tooltip', 'meta' => array('tip' => pht('Oldest open task, excluding those with Low or Wishlist priority.'), 'size' => 200)), pht('Oldest (Pri)')); $cclass[] = 'n'; list($ignored, $window_epoch) = $this->getWindow(); $edate = phabricator_datetime($window_epoch, $viewer); $cname[] = javelin_tag('span', array('sigil' => 'has-tooltip', 'meta' => array('tip' => pht('Closed after %s', $edate), 'size' => 260)), pht('Recently Closed')); $cclass[] = 'n'; $table = new AphrontTableView($rows); $table->setHeaders($cname); $table->setColumnClasses($cclass); $table->makeSortable($request->getRequestURI(), 'order', $order, $reverse, array('name', null, null, null, null, null, null, 'total', 'oldest-all', 'oldest-pri', 'closed')); $panel = new PHUIObjectBoxView(); $panel->setHeaderText($header); $panel->setTable($table); $tokens = array(); if ($project_handle) { $tokens = array($project_handle); } $filter = $this->renderReportFilters($tokens, $has_window = true); return array($filter, $panel); }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $files = array(); $parent_task = null; $template_id = null; if ($this->id) { $task = id(new ManiphestTask())->load($this->id); if (!$task) { return new Aphront404Response(); } } else { $task = new ManiphestTask(); $task->setPriority(ManiphestTaskPriority::PRIORITY_TRIAGE); $task->setAuthorPHID($user->getPHID()); // These allow task creation with defaults. if (!$request->isFormPost()) { $task->setTitle($request->getStr('title')); $default_projects = $request->getStr('projects'); if ($default_projects) { $task->setProjectPHIDs(explode(';', $default_projects)); } } $file_phids = $request->getArr('files', array()); if (!$file_phids) { // Allow a single 'file' key instead, mostly since Mac OS X urlencodes // square brackets in URLs when passed to 'open', so you can't 'open' // a URL like '?files[]=xyz' and have PHP interpret it correctly. $phid = $request->getStr('file'); if ($phid) { $file_phids = array($phid); } } if ($file_phids) { $files = id(new PhabricatorFile())->loadAllWhere('phid IN (%Ls)', $file_phids); } $template_id = $request->getInt('template'); // You can only have a parent task if you're creating a new task. $parent_id = $request->getInt('parent'); if ($parent_id) { $parent_task = id(new ManiphestTask())->load($parent_id); } } $errors = array(); $e_title = true; $extensions = ManiphestTaskExtensions::newExtensions(); $aux_fields = $extensions->getAuxiliaryFieldSpecifications(); if ($request->isFormPost()) { $changes = array(); $new_title = $request->getStr('title'); $new_desc = $request->getStr('description'); $new_status = $request->getStr('status'); $workflow = ''; if ($task->getID()) { if ($new_title != $task->getTitle()) { $changes[ManiphestTransactionType::TYPE_TITLE] = $new_title; } if ($new_desc != $task->getDescription()) { $changes[ManiphestTransactionType::TYPE_DESCRIPTION] = $new_desc; } if ($new_status != $task->getStatus()) { $changes[ManiphestTransactionType::TYPE_STATUS] = $new_status; } } else { $task->setTitle($new_title); $task->setDescription($new_desc); $changes[ManiphestTransactionType::TYPE_STATUS] = ManiphestTaskStatus::STATUS_OPEN; $workflow = 'create'; } $owner_tokenizer = $request->getArr('assigned_to'); $owner_phid = reset($owner_tokenizer); if (!strlen($new_title)) { $e_title = 'Required'; $errors[] = 'Title is required.'; } foreach ($aux_fields as $aux_field) { $aux_field->setValueFromRequest($request); if ($aux_field->isRequired() && !strlen($aux_field->getValue())) { $errors[] = $aux_field->getLabel() . ' is required.'; $aux_field->setError('Required'); } if (strlen($aux_field->getValue())) { try { $aux_field->validate(); } catch (Exception $e) { $errors[] = $e->getMessage(); $aux_field->setError('Invalid'); } } } if ($errors) { $task->setPriority($request->getInt('priority')); $task->setOwnerPHID($owner_phid); $task->setCCPHIDs($request->getArr('cc')); $task->setProjectPHIDs($request->getArr('projects')); } else { if ($request->getInt('priority') != $task->getPriority()) { $changes[ManiphestTransactionType::TYPE_PRIORITY] = $request->getInt('priority'); } if ($owner_phid != $task->getOwnerPHID()) { $changes[ManiphestTransactionType::TYPE_OWNER] = $owner_phid; } if ($request->getArr('cc') != $task->getCCPHIDs()) { $changes[ManiphestTransactionType::TYPE_CCS] = $request->getArr('cc'); } $new_proj_arr = $request->getArr('projects'); $new_proj_arr = array_values($new_proj_arr); sort($new_proj_arr); $cur_proj_arr = $task->getProjectPHIDs(); $cur_proj_arr = array_values($cur_proj_arr); sort($cur_proj_arr); if ($new_proj_arr != $cur_proj_arr) { $changes[ManiphestTransactionType::TYPE_PROJECTS] = $new_proj_arr; } if ($files) { $file_map = mpull($files, 'getPHID'); $file_map = array_fill_keys($file_map, array()); $changes[ManiphestTransactionType::TYPE_ATTACH] = array(PhabricatorPHIDConstants::PHID_TYPE_FILE => $file_map); } $content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_WEB, array('ip' => $request->getRemoteAddr())); $template = new ManiphestTransaction(); $template->setAuthorPHID($user->getPHID()); $template->setContentSource($content_source); $transactions = array(); foreach ($changes as $type => $value) { $transaction = clone $template; $transaction->setTransactionType($type); $transaction->setNewValue($value); $transactions[] = $transaction; } if ($aux_fields) { $task->loadAndAttachAuxiliaryAttributes(); foreach ($aux_fields as $aux_field) { $transaction = clone $template; $transaction->setTransactionType(ManiphestTransactionType::TYPE_AUXILIARY); $aux_key = $aux_field->getAuxiliaryKey(); $transaction->setMetadataValue('aux:key', $aux_key); $transaction->setNewValue($aux_field->getValueForStorage()); $transactions[] = $transaction; } } if ($transactions) { $is_new = !$task->getID(); $event = new PhabricatorEvent(PhabricatorEventType::TYPE_MANIPHEST_WILLEDITTASK, array('task' => $task, 'new' => $is_new, 'transactions' => $transactions)); $event->setUser($user); $event->setAphrontRequest($request); PhutilEventEngine::dispatchEvent($event); $task = $event->getValue('task'); $transactions = $event->getValue('transactions'); $editor = new ManiphestTransactionEditor(); $editor->setAuxiliaryFields($aux_fields); $editor->applyTransactions($task, $transactions); $event = new PhabricatorEvent(PhabricatorEventType::TYPE_MANIPHEST_DIDEDITTASK, array('task' => $task, 'new' => $is_new, 'transactions' => $transactions)); $event->setUser($user); $event->setAphrontRequest($request); PhutilEventEngine::dispatchEvent($event); } if ($parent_task) { $type_task = PhabricatorPHIDConstants::PHID_TYPE_TASK; // NOTE: It's safe to simply apply this transaction without doing // cycle detection because we know the new task has no children. $new_value = $parent_task->getAttached(); $new_value[$type_task][$task->getPHID()] = array(); $parent_xaction = clone $template; $attach_type = ManiphestTransactionType::TYPE_ATTACH; $parent_xaction->setTransactionType($attach_type); $parent_xaction->setNewValue($new_value); $editor = new ManiphestTransactionEditor(); $editor->setAuxiliaryFields($aux_fields); $editor->applyTransactions($parent_task, array($parent_xaction)); $workflow = $parent_task->getID(); } $redirect_uri = '/T' . $task->getID(); if ($workflow) { $redirect_uri .= '?workflow=' . $workflow; } return id(new AphrontRedirectResponse())->setURI($redirect_uri); } } else { if (!$task->getID()) { $task->setCCPHIDs(array($user->getPHID())); if ($template_id) { $template_task = id(new ManiphestTask())->load($template_id); if ($template_task) { $task->setCCPHIDs($template_task->getCCPHIDs()); $task->setProjectPHIDs($template_task->getProjectPHIDs()); $task->setOwnerPHID($template_task->getOwnerPHID()); } } } } $phids = array_merge(array($task->getOwnerPHID()), $task->getCCPHIDs(), $task->getProjectPHIDs()); if ($parent_task) { $phids[] = $parent_task->getPHID(); } $phids = array_filter($phids); $phids = array_unique($phids); $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles($phids); $tvalues = mpull($handles, 'getFullName', 'getPHID'); $error_view = null; if ($errors) { $error_view = new AphrontErrorView(); $error_view->setErrors($errors); $error_view->setTitle('Form Errors'); } $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); if ($task->getOwnerPHID()) { $assigned_value = array($task->getOwnerPHID() => $handles[$task->getOwnerPHID()]->getFullName()); } else { $assigned_value = array(); } if ($task->getCCPHIDs()) { $cc_value = array_select_keys($tvalues, $task->getCCPHIDs()); } else { $cc_value = array(); } if ($task->getProjectPHIDs()) { $projects_value = array_select_keys($tvalues, $task->getProjectPHIDs()); } else { $projects_value = array(); } $cancel_id = nonempty($task->getID(), $template_id); if ($cancel_id) { $cancel_uri = '/T' . $cancel_id; } else { $cancel_uri = '/maniphest/'; } if ($task->getID()) { $button_name = 'Save Task'; $header_name = 'Edit Task'; } else { if ($parent_task) { $cancel_uri = '/T' . $parent_task->getID(); $button_name = 'Create Task'; $header_name = 'Create New Subtask'; } else { $button_name = 'Create Task'; $header_name = 'Create New Task'; } } require_celerity_resource('maniphest-task-edit-css'); $project_tokenizer_id = celerity_generate_unique_node_id(); $form = new AphrontFormView(); $form->setUser($user)->setAction($request->getRequestURI()->getPath())->addHiddenInput('template', $template_id); if ($parent_task) { $form->appendChild(id(new AphrontFormStaticControl())->setLabel('Parent Task')->setValue($handles[$parent_task->getPHID()]->getFullName()))->addHiddenInput('parent', $parent_task->getID()); } $form->appendChild(id(new AphrontFormTextAreaControl())->setLabel('Title')->setName('title')->setError($e_title)->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_SHORT)->setValue($task->getTitle())); if ($task->getID()) { // Only show this in "edit" mode, not "create" mode, since creating a // non-open task is kind of silly and it would just clutter up the // "create" interface. $form->appendChild(id(new AphrontFormSelectControl())->setLabel('Status')->setName('status')->setValue($task->getStatus())->setOptions(ManiphestTaskStatus::getTaskStatusMap())); } $form->appendChild(id(new AphrontFormTokenizerControl())->setLabel('Assigned To')->setName('assigned_to')->setValue($assigned_value)->setUser($user)->setDatasource('/typeahead/common/users/')->setLimit(1))->appendChild(id(new AphrontFormTokenizerControl())->setLabel('CC')->setName('cc')->setValue($cc_value)->setUser($user)->setDatasource('/typeahead/common/mailable/'))->appendChild(id(new AphrontFormSelectControl())->setLabel('Priority')->setName('priority')->setOptions($priority_map)->setValue($task->getPriority()))->appendChild(id(new AphrontFormTokenizerControl())->setLabel('Projects')->setName('projects')->setValue($projects_value)->setID($project_tokenizer_id)->setCaption(javelin_render_tag('a', array('href' => '/project/create/', 'mustcapture' => true, 'sigil' => 'project-create'), 'Create New Project'))->setDatasource('/typeahead/common/projects/')); if ($aux_fields) { if (!$request->isFormPost()) { $task->loadAndAttachAuxiliaryAttributes(); foreach ($aux_fields as $aux_field) { $aux_key = $aux_field->getAuxiliaryKey(); $value = $task->getAuxiliaryAttribute($aux_key); $aux_field->setValueFromStorage($value); } } foreach ($aux_fields as $aux_field) { if ($aux_field->isRequired() && !$aux_field->getError() && !$aux_field->getValue()) { $aux_field->setError(true); } $aux_control = $aux_field->renderControl(); $form->appendChild($aux_control); } } require_celerity_resource('aphront-error-view-css'); Javelin::initBehavior('maniphest-project-create', array('tokenizerID' => $project_tokenizer_id)); if ($files) { $file_display = array(); foreach ($files as $file) { $file_display[] = phutil_escape_html($file->getName()); } $file_display = implode('<br />', $file_display); $form->appendChild(id(new AphrontFormMarkupControl())->setLabel('Files')->setValue($file_display)); foreach ($files as $ii => $file) { $form->addHiddenInput('files[' . $ii . ']', $file->getPHID()); } } $email_create = PhabricatorEnv::getEnvConfig('metamta.maniphest.public-create-email'); $email_hint = null; if (!$task->getID() && $email_create) { $email_hint = 'You can also create tasks by sending an email to: ' . '<tt>' . phutil_escape_html($email_create) . '</tt>'; } $panel_id = celerity_generate_unique_node_id(); $form->appendChild(id(new AphrontFormTextAreaControl())->setLabel('Description')->setName('description')->setID('description-textarea')->setCaption($email_hint)->setValue($task->getDescription())); if (!$task->getID()) { $form->appendChild(id(new AphrontFormDragAndDropUploadControl())->setLabel('Attached Files')->setName('files')->setDragAndDropTarget($panel_id)->setActivatedClass('aphront-panel-view-drag-and-drop')); } $form->appendChild(id(new AphrontFormSubmitControl())->addCancelButton($cancel_uri)->setValue($button_name)); $panel = new AphrontPanelView(); $panel->setWidth(AphrontPanelView::WIDTH_FULL); $panel->setHeader($header_name); $panel->setID($panel_id); $panel->appendChild($form); $description_preview_panel = '<div class="aphront-panel-preview aphront-panel-preview-full"> <div class="maniphest-description-preview-header"> Description Preview </div> <div id="description-preview"> <div class="aphront-panel-preview-loading-text"> Loading preview... </div> </div> </div>'; Javelin::initBehavior('maniphest-description-preview', array('preview' => 'description-preview', 'textarea' => 'description-textarea', 'uri' => '/maniphest/task/descriptionpreview/')); return $this->buildStandardPageResponse(array($error_view, $panel, $description_preview_panel), array('title' => $header_name)); }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $e_title = null; $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); $task = id(new ManiphestTask())->load($this->id); if (!$task) { return new Aphront404Response(); } $workflow = $request->getStr('workflow'); $parent_task = null; if ($workflow && is_numeric($workflow)) { $parent_task = id(new ManiphestTask())->load($workflow); } $transactions = id(new ManiphestTransaction())->loadAllWhere('taskID = %d ORDER BY id ASC', $task->getID()); $e_commit = PhabricatorEdgeConfig::TYPE_TASK_HAS_COMMIT; $e_dep_on = PhabricatorEdgeConfig::TYPE_TASK_DEPENDS_ON_TASK; $e_dep_by = PhabricatorEdgeConfig::TYPE_TASK_DEPENDED_ON_BY_TASK; $e_rev = PhabricatorEdgeConfig::TYPE_TASK_HAS_RELATED_DREV; $phid = $task->getPHID(); $query = id(new PhabricatorEdgeQuery())->withSourcePHIDs(array($phid))->withEdgeTypes(array($e_commit, $e_dep_on, $e_dep_by, $e_rev)); $edges = $query->execute(); $commit_phids = array_keys($edges[$phid][$e_commit]); $dep_on_tasks = array_keys($edges[$phid][$e_dep_on]); $dep_by_tasks = array_keys($edges[$phid][$e_dep_by]); $revs = array_keys($edges[$phid][$e_rev]); $phids = array_fill_keys($query->getDestinationPHIDs(), true); foreach ($transactions as $transaction) { foreach ($transaction->extractPHIDs() as $phid) { $phids[$phid] = true; } } foreach ($task->getCCPHIDs() as $phid) { $phids[$phid] = true; } foreach ($task->getProjectPHIDs() as $phid) { $phids[$phid] = true; } if ($task->getOwnerPHID()) { $phids[$task->getOwnerPHID()] = true; } $phids[$task->getAuthorPHID()] = true; $attached = $task->getAttached(); foreach ($attached as $type => $list) { foreach ($list as $phid => $info) { $phids[$phid] = true; } } if ($parent_task) { $phids[$parent_task->getPHID()] = true; } $phids = array_keys($phids); $handles = $this->loadViewerHandles($phids); $dict = array(); $dict['Status'] = '<strong>' . ManiphestTaskStatus::getTaskStatusFullName($task->getStatus()) . '</strong>'; $dict['Assigned To'] = $task->getOwnerPHID() ? $handles[$task->getOwnerPHID()]->renderLink() : '<em>None</em>'; $dict['Priority'] = ManiphestTaskPriority::getTaskPriorityName($task->getPriority()); $cc = $task->getCCPHIDs(); if ($cc) { $cc_links = array(); foreach ($cc as $phid) { $cc_links[] = $handles[$phid]->renderLink(); } $dict['CC'] = implode(', ', $cc_links); } else { $dict['CC'] = '<em>None</em>'; } $dict['Author'] = $handles[$task->getAuthorPHID()]->renderLink(); $source = $task->getOriginalEmailSource(); if ($source) { $subject = '[T' . $task->getID() . '] ' . $task->getTitle(); $dict['From Email'] = phutil_render_tag('a', array('href' => 'mailto:' . $source . '?subject=' . $subject), phutil_escape_html($source)); } $projects = $task->getProjectPHIDs(); if ($projects) { $project_links = array(); foreach ($projects as $phid) { $project_links[] = $handles[$phid]->renderLink(); } $dict['Projects'] = implode(', ', $project_links); } else { $dict['Projects'] = '<em>None</em>'; } $extensions = ManiphestTaskExtensions::newExtensions(); $aux_fields = $extensions->getAuxiliaryFieldSpecifications(); if ($aux_fields) { $task->loadAndAttachAuxiliaryAttributes(); foreach ($aux_fields as $aux_field) { $aux_key = $aux_field->getAuxiliaryKey(); $aux_field->setValue($task->getAuxiliaryAttribute($aux_key)); $value = $aux_field->renderForDetailView(); if (strlen($value)) { $dict[$aux_field->getLabel()] = $value; } } } if ($dep_by_tasks) { $dict['Dependent Tasks'] = $this->renderHandleList(array_select_keys($handles, $dep_by_tasks)); } if ($dep_on_tasks) { $dict['Depends On'] = $this->renderHandleList(array_select_keys($handles, $dep_on_tasks)); } if ($revs) { $dict['Revisions'] = $this->renderHandleList(array_select_keys($handles, $revs)); } if ($commit_phids) { $dict['Commits'] = $this->renderHandleList(array_select_keys($handles, $commit_phids)); } $file_infos = idx($attached, PhabricatorPHIDConstants::PHID_TYPE_FILE); if ($file_infos) { $file_phids = array_keys($file_infos); $files = id(new PhabricatorFile())->loadAllWhere('phid IN (%Ls)', $file_phids); $views = array(); foreach ($files as $file) { $view = new AphrontFilePreviewView(); $view->setFile($file); $views[] = $view->render(); } $dict['Files'] = implode('', $views); } $context_bar = null; if ($parent_task) { $context_bar = new AphrontContextBarView(); $context_bar->addButton(phutil_render_tag('a', array('href' => '/maniphest/task/create/?parent=' . $parent_task->getID(), 'class' => 'green button'), 'Create Another Subtask')); $context_bar->appendChild('Created a subtask of <strong>' . $handles[$parent_task->getPHID()]->renderLink() . '</strong>'); } else { if ($workflow == 'create') { $context_bar = new AphrontContextBarView(); $context_bar->addButton('<label>Create Another:</label>'); $context_bar->addButton(phutil_render_tag('a', array('href' => '/maniphest/task/create/?template=' . $task->getID(), 'class' => 'green button'), 'Similar Task')); $context_bar->addButton(phutil_render_tag('a', array('href' => '/maniphest/task/create/', 'class' => 'green button'), 'Empty Task')); $context_bar->appendChild('New task created.'); } } $actions = array(); $action = new AphrontHeadsupActionView(); $action->setName('Edit Task'); $action->setURI('/maniphest/task/edit/' . $task->getID() . '/'); $action->setClass('action-edit'); $actions[] = $action; require_celerity_resource('phabricator-flag-css'); $flag = PhabricatorFlagQuery::loadUserFlag($user, $task->getPHID()); if ($flag) { $class = PhabricatorFlagColor::getCSSClass($flag->getColor()); $color = PhabricatorFlagColor::getColorName($flag->getColor()); $action = new AphrontHeadsupActionView(); $action->setClass('flag-clear ' . $class); $action->setURI('/flag/delete/' . $flag->getID() . '/'); $action->setName('Remove ' . $color . ' Flag'); $action->setWorkflow(true); $actions[] = $action; } else { $action = new AphrontHeadsupActionView(); $action->setClass('phabricator-flag-ghost'); $action->setURI('/flag/edit/' . $task->getPHID() . '/'); $action->setName('Flag Task'); $action->setWorkflow(true); $actions[] = $action; } require_celerity_resource('phabricator-object-selector-css'); require_celerity_resource('javelin-behavior-phabricator-object-selector'); $action = new AphrontHeadsupActionView(); $action->setName('Merge Duplicates'); $action->setURI('/search/attach/' . $task->getPHID() . '/TASK/merge/'); $action->setWorkflow(true); $action->setClass('action-merge'); $actions[] = $action; $action = new AphrontHeadsupActionView(); $action->setName('Create Subtask'); $action->setURI('/maniphest/task/create/?parent=' . $task->getID()); $action->setClass('action-branch'); $actions[] = $action; $action = new AphrontHeadsupActionView(); $action->setName('Edit Dependencies'); $action->setURI('/search/attach/' . $task->getPHID() . '/TASK/dependencies/'); $action->setWorkflow(true); $action->setClass('action-dependencies'); $actions[] = $action; $action = new AphrontHeadsupActionView(); $action->setName('Edit Differential Revisions'); $action->setURI('/search/attach/' . $task->getPHID() . '/DREV/'); $action->setWorkflow(true); $action->setClass('action-attach'); $actions[] = $action; $action_list = new AphrontHeadsupActionListView(); $action_list->setActions($actions); $headsup_panel = new AphrontHeadsupView(); $headsup_panel->setObjectName('T' . $task->getID()); $headsup_panel->setHeader($task->getTitle()); $headsup_panel->setActionList($action_list); $headsup_panel->setProperties($dict); $engine = new PhabricatorMarkupEngine(); $engine->setViewer($user); $engine->addObject($task, ManiphestTask::MARKUP_FIELD_DESCRIPTION); foreach ($transactions as $xaction) { if ($xaction->hasComments()) { $engine->addObject($xaction, ManiphestTransaction::MARKUP_FIELD_BODY); } } $engine->process(); $headsup_panel->appendChild('<div class="phabricator-remarkup">' . $engine->getOutput($task, ManiphestTask::MARKUP_FIELD_DESCRIPTION) . '</div>'); $transaction_types = ManiphestTransactionType::getTransactionTypeMap(); $resolution_types = ManiphestTaskStatus::getTaskStatusMap(); if ($task->getStatus() == ManiphestTaskStatus::STATUS_OPEN) { $resolution_types = array_select_keys($resolution_types, array(ManiphestTaskStatus::STATUS_CLOSED_RESOLVED, ManiphestTaskStatus::STATUS_CLOSED_WONTFIX, ManiphestTaskStatus::STATUS_CLOSED_INVALID, ManiphestTaskStatus::STATUS_CLOSED_SPITE)); } else { $resolution_types = array(ManiphestTaskStatus::STATUS_OPEN => 'Reopened'); $transaction_types[ManiphestTransactionType::TYPE_STATUS] = 'Reopen Task'; unset($transaction_types[ManiphestTransactionType::TYPE_PRIORITY]); unset($transaction_types[ManiphestTransactionType::TYPE_OWNER]); } $default_claim = array($user->getPHID() => $user->getUsername() . ' (' . $user->getRealName() . ')'); $draft = id(new PhabricatorDraft())->loadOneWhere('authorPHID = %s AND draftKey = %s', $user->getPHID(), $task->getPHID()); if ($draft) { $draft_text = $draft->getDraft(); } else { $draft_text = null; } $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); if ($is_serious) { // Prevent tasks from being closed "out of spite" in serious business // installs. unset($resolution_types[ManiphestTaskStatus::STATUS_CLOSED_SPITE]); } $comment_form = new AphrontFormView(); $comment_form->setUser($user)->setAction('/maniphest/transaction/save/')->setEncType('multipart/form-data')->addHiddenInput('taskID', $task->getID())->appendChild(id(new AphrontFormSelectControl())->setLabel('Action')->setName('action')->setOptions($transaction_types)->setID('transaction-action'))->appendChild(id(new AphrontFormSelectControl())->setLabel('Resolution')->setName('resolution')->setControlID('resolution')->setControlStyle('display: none')->setOptions($resolution_types))->appendChild(id(new AphrontFormTokenizerControl())->setLabel('Assign To')->setName('assign_to')->setControlID('assign_to')->setControlStyle('display: none')->setID('assign-tokenizer')->setDisableBehavior(true))->appendChild(id(new AphrontFormTokenizerControl())->setLabel('CCs')->setName('ccs')->setControlID('ccs')->setControlStyle('display: none')->setID('cc-tokenizer')->setDisableBehavior(true))->appendChild(id(new AphrontFormSelectControl())->setLabel('Priority')->setName('priority')->setOptions($priority_map)->setControlID('priority')->setControlStyle('display: none')->setValue($task->getPriority()))->appendChild(id(new AphrontFormTokenizerControl())->setLabel('Projects')->setName('projects')->setControlID('projects')->setControlStyle('display: none')->setID('projects-tokenizer')->setDisableBehavior(true))->appendChild(id(new AphrontFormFileControl())->setLabel('File')->setName('file')->setControlID('file')->setControlStyle('display: none'))->appendChild(id(new PhabricatorRemarkupControl())->setLabel('Comments')->setName('comments')->setValue($draft_text)->setID('transaction-comments'))->appendChild(id(new AphrontFormDragAndDropUploadControl())->setLabel('Attached Files')->setName('files')->setActivatedClass('aphront-panel-view-drag-and-drop'))->appendChild(id(new AphrontFormSubmitControl())->setValue($is_serious ? 'Submit' : 'Avast!')); $control_map = array(ManiphestTransactionType::TYPE_STATUS => 'resolution', ManiphestTransactionType::TYPE_OWNER => 'assign_to', ManiphestTransactionType::TYPE_CCS => 'ccs', ManiphestTransactionType::TYPE_PRIORITY => 'priority', ManiphestTransactionType::TYPE_PROJECTS => 'projects', ManiphestTransactionType::TYPE_ATTACH => 'file'); $tokenizer_map = array(ManiphestTransactionType::TYPE_PROJECTS => array('id' => 'projects-tokenizer', 'src' => '/typeahead/common/projects/', 'ondemand' => PhabricatorEnv::getEnvConfig('tokenizer.ondemand'), 'placeholder' => 'Type a project name...'), ManiphestTransactionType::TYPE_OWNER => array('id' => 'assign-tokenizer', 'src' => '/typeahead/common/users/', 'value' => $default_claim, 'limit' => 1, 'ondemand' => PhabricatorEnv::getEnvConfig('tokenizer.ondemand'), 'placeholder' => 'Type a user name...'), ManiphestTransactionType::TYPE_CCS => array('id' => 'cc-tokenizer', 'src' => '/typeahead/common/mailable/', 'ondemand' => PhabricatorEnv::getEnvConfig('tokenizer.ondemand'), 'placeholder' => 'Type a user or mailing list...')); Javelin::initBehavior('maniphest-transaction-controls', array('select' => 'transaction-action', 'controlMap' => $control_map, 'tokenizers' => $tokenizer_map)); Javelin::initBehavior('maniphest-transaction-preview', array('uri' => '/maniphest/transaction/preview/' . $task->getID() . '/', 'preview' => 'transaction-preview', 'comments' => 'transaction-comments', 'action' => 'transaction-action', 'map' => $control_map, 'tokenizers' => $tokenizer_map)); $comment_panel = new AphrontPanelView(); $comment_panel->appendChild($comment_form); $comment_panel->addClass('aphront-panel-accent'); $comment_panel->setHeader($is_serious ? 'Add Comment' : 'Weigh In'); $preview_panel = '<div class="aphront-panel-preview"> <div id="transaction-preview"> <div class="aphront-panel-preview-loading-text"> Loading preview... </div> </div> </div>'; $transaction_view = new ManiphestTransactionListView(); $transaction_view->setTransactions($transactions); $transaction_view->setHandles($handles); $transaction_view->setUser($user); $transaction_view->setAuxiliaryFields($aux_fields); $transaction_view->setMarkupEngine($engine); PhabricatorFeedStoryNotification::updateObjectNotificationViews($user, $task->getPHID()); return $this->buildStandardPageResponse(array($context_bar, $headsup_panel, $transaction_view, $comment_panel, $preview_panel), array('title' => 'T' . $task->getID() . ' ' . $task->getTitle(), 'pageObjects' => array($task->getPHID()))); }
private function renderConditionValueAsText(HeraldCondition $condition, PhabricatorHandleList $handles) { $value = $condition->getValue(); if (!is_array($value)) { $value = array($value); } switch ($condition->getFieldName()) { case self::FIELD_TASK_PRIORITY: $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); foreach ($value as $index => $val) { $name = idx($priority_map, $val); if ($name) { $value[$index] = $name; } } break; case self::FIELD_TASK_STATUS: $status_map = ManiphestTaskStatus::getTaskStatusMap(); foreach ($value as $index => $val) { $name = idx($status_map, $val); if ($name) { $value[$index] = $name; } } break; case HeraldPreCommitRefAdapter::FIELD_REF_CHANGE: $change_map = PhabricatorRepositoryPushLog::getHeraldChangeFlagConditionOptions(); foreach ($value as $index => $val) { $name = idx($change_map, $val); if ($name) { $value[$index] = $name; } } break; default: foreach ($value as $index => $val) { $handle = $handles->getHandleIfExists($val); if ($handle) { $value[$index] = $handle->renderLink(); } } break; } $value = phutil_implode_html(', ', $value); return $value; }
private function setupEditorBehavior(HeraldRule $rule, array $handles, HeraldAdapter $adapter) { $serial_conditions = array(array('default', 'default', '')); if ($rule->getConditions()) { $serial_conditions = array(); foreach ($rule->getConditions() as $condition) { $value = $condition->getValue(); switch ($condition->getFieldName()) { case HeraldAdapter::FIELD_TASK_PRIORITY: $value_map = array(); $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); foreach ($value as $priority) { $value_map[$priority] = idx($priority_map, $priority); } $value = $value_map; break; case HeraldAdapter::FIELD_TASK_STATUS: $value_map = array(); $status_map = ManiphestTaskStatus::getTaskStatusMap(); foreach ($value as $status) { $value_map[$status] = idx($status_map, $status); } $value = $value_map; break; default: if (is_array($value)) { $value_map = array(); foreach ($value as $k => $fbid) { $value_map[$fbid] = $handles[$fbid]->getName(); } $value = $value_map; } break; } $serial_conditions[] = array($condition->getFieldName(), $condition->getFieldCondition(), $value); } } $serial_actions = array(array('default', '')); if ($rule->getActions()) { $serial_actions = array(); foreach ($rule->getActions() as $action) { switch ($action->getAction()) { case HeraldAdapter::ACTION_FLAG: case HeraldAdapter::ACTION_BLOCK: $current_value = $action->getTarget(); break; default: if (is_array($action->getTarget())) { $target_map = array(); foreach ((array) $action->getTarget() as $fbid) { $target_map[$fbid] = $handles[$fbid]->getName(); } $current_value = $target_map; } else { $current_value = $action->getTarget(); } break; } $serial_actions[] = array($action->getAction(), $current_value); } } $all_rules = $this->loadRulesThisRuleMayDependUpon($rule); $all_rules = mpull($all_rules, 'getName', 'getPHID'); asort($all_rules); $all_fields = $adapter->getFieldNameMap(); $all_conditions = $adapter->getConditionNameMap(); $all_actions = $adapter->getActionNameMap($rule->getRuleType()); $fields = $adapter->getFields(); $field_map = array_select_keys($all_fields, $fields); // Populate any fields which exist in the rule but which we don't know the // names of, so that saving a rule without touching anything doesn't change // it. foreach ($rule->getConditions() as $condition) { $field_name = $condition->getFieldName(); if (empty($field_map[$field_name])) { $field_map[$field_name] = pht('<Unknown Field "%s">', $field_name); } } $actions = $adapter->getActions($rule->getRuleType()); $action_map = array_select_keys($all_actions, $actions); // Populate any actions which exist in the rule but which we don't know the // names of, so that saving a rule without touching anything doesn't change // it. foreach ($rule->getActions() as $action) { $action_name = $action->getAction(); if (empty($action_map[$action_name])) { $action_map[$action_name] = pht('<Unknown Action "%s">', $action_name); } } $config_info = array(); $config_info['fields'] = $field_map; $config_info['conditions'] = $all_conditions; $config_info['actions'] = $action_map; foreach ($config_info['fields'] as $field => $name) { try { $field_conditions = $adapter->getConditionsForField($field); } catch (Exception $ex) { $field_conditions = array(HeraldAdapter::CONDITION_UNCONDITIONALLY); } $config_info['conditionMap'][$field] = $field_conditions; } foreach ($config_info['fields'] as $field => $fname) { foreach ($config_info['conditionMap'][$field] as $condition) { $value_type = $adapter->getValueTypeForFieldAndCondition($field, $condition); $config_info['values'][$field][$condition] = $value_type; } } $config_info['rule_type'] = $rule->getRuleType(); foreach ($config_info['actions'] as $action => $name) { try { $action_value = $adapter->getValueTypeForAction($action, $rule->getRuleType()); } catch (Exception $ex) { $action_value = array(HeraldAdapter::VALUE_NONE); } $config_info['targets'][$action] = $action_value; } $changeflag_options = PhabricatorRepositoryPushLog::getHeraldChangeFlagConditionOptions(); Javelin::initBehavior('herald-rule-editor', array('root' => 'herald-rule-edit-form', 'conditions' => (object) $serial_conditions, 'actions' => (object) $serial_actions, 'select' => array(HeraldAdapter::VALUE_CONTENT_SOURCE => array('options' => PhabricatorContentSource::getSourceNameMap(), 'default' => PhabricatorContentSource::SOURCE_WEB), HeraldAdapter::VALUE_FLAG_COLOR => array('options' => PhabricatorFlagColor::getColorNameMap(), 'default' => PhabricatorFlagColor::COLOR_BLUE), HeraldPreCommitRefAdapter::VALUE_REF_TYPE => array('options' => array(PhabricatorRepositoryPushLog::REFTYPE_BRANCH => pht('branch (git/hg)'), PhabricatorRepositoryPushLog::REFTYPE_TAG => pht('tag (git)'), PhabricatorRepositoryPushLog::REFTYPE_BOOKMARK => pht('bookmark (hg)')), 'default' => PhabricatorRepositoryPushLog::REFTYPE_BRANCH), HeraldPreCommitRefAdapter::VALUE_REF_CHANGE => array('options' => $changeflag_options, 'default' => PhabricatorRepositoryPushLog::CHANGEFLAG_ADD)), 'template' => $this->buildTokenizerTemplates($handles) + array('rules' => $all_rules), 'author' => array($rule->getAuthorPHID() => $handles[$rule->getAuthorPHID()]->getName()), 'info' => $config_info)); }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $e_title = null; $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); $task = id(new ManiphestTaskQuery())->setViewer($user)->withIDs(array($this->id))->needSubscriberPHIDs(true)->executeOne(); if (!$task) { return new Aphront404Response(); } $workflow = $request->getStr('workflow'); $parent_task = null; if ($workflow && is_numeric($workflow)) { $parent_task = id(new ManiphestTaskQuery())->setViewer($user)->withIDs(array($workflow))->executeOne(); } $field_list = PhabricatorCustomField::getObjectFields($task, PhabricatorCustomField::ROLE_VIEW); $field_list->setViewer($user)->readFieldsFromStorage($task); $e_commit = ManiphestTaskHasCommitEdgeType::EDGECONST; $e_dep_on = ManiphestTaskDependsOnTaskEdgeType::EDGECONST; $e_dep_by = ManiphestTaskDependedOnByTaskEdgeType::EDGECONST; $e_rev = ManiphestTaskHasRevisionEdgeType::EDGECONST; $e_mock = ManiphestTaskHasMockEdgeType::EDGECONST; $phid = $task->getPHID(); $query = id(new PhabricatorEdgeQuery())->withSourcePHIDs(array($phid))->withEdgeTypes(array($e_commit, $e_dep_on, $e_dep_by, $e_rev, $e_mock)); $edges = idx($query->execute(), $phid); $phids = array_fill_keys($query->getDestinationPHIDs(), true); if ($task->getOwnerPHID()) { $phids[$task->getOwnerPHID()] = true; } $phids[$task->getAuthorPHID()] = true; $attached = $task->getAttached(); foreach ($attached as $type => $list) { foreach ($list as $phid => $info) { $phids[$phid] = true; } } if ($parent_task) { $phids[$parent_task->getPHID()] = true; } $phids = array_keys($phids); $handles = $user->loadHandles($phids); $info_view = null; if ($parent_task) { $info_view = new PHUIInfoView(); $info_view->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $info_view->addButton(id(new PHUIButtonView())->setTag('a')->setHref('/maniphest/task/create/?parent=' . $parent_task->getID())->setText(pht('Create Another Subtask'))); $info_view->appendChild(hsprintf('Created a subtask of <strong>%s</strong>.', $handles->renderHandle($parent_task->getPHID()))); } else { if ($workflow == 'create') { $info_view = new PHUIInfoView(); $info_view->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $info_view->addButton(id(new PHUIButtonView())->setTag('a')->setHref('/maniphest/task/create/?template=' . $task->getID())->setText(pht('Similar Task'))); $info_view->addButton(id(new PHUIButtonView())->setTag('a')->setHref('/maniphest/task/create/')->setText(pht('Empty Task'))); $info_view->appendChild(pht('New task created. Create another?')); } } $engine = new PhabricatorMarkupEngine(); $engine->setViewer($user); $engine->setContextObject($task); $engine->addObject($task, ManiphestTask::MARKUP_FIELD_DESCRIPTION); $timeline = $this->buildTransactionTimeline($task, new ManiphestTransactionQuery(), $engine); $resolution_types = ManiphestTaskStatus::getTaskStatusMap(); $transaction_types = array(PhabricatorTransactions::TYPE_COMMENT => pht('Comment'), ManiphestTransaction::TYPE_STATUS => pht('Change Status'), ManiphestTransaction::TYPE_OWNER => pht('Reassign / Claim'), PhabricatorTransactions::TYPE_SUBSCRIBERS => pht('Add CCs'), ManiphestTransaction::TYPE_PRIORITY => pht('Change Priority'), PhabricatorTransactions::TYPE_EDGE => pht('Associate Projects')); // Remove actions the user doesn't have permission to take. $requires = array(ManiphestTransaction::TYPE_OWNER => ManiphestEditAssignCapability::CAPABILITY, ManiphestTransaction::TYPE_PRIORITY => ManiphestEditPriorityCapability::CAPABILITY, PhabricatorTransactions::TYPE_EDGE => ManiphestEditProjectsCapability::CAPABILITY, ManiphestTransaction::TYPE_STATUS => ManiphestEditStatusCapability::CAPABILITY); foreach ($transaction_types as $type => $name) { if (isset($requires[$type])) { if (!$this->hasApplicationCapability($requires[$type])) { unset($transaction_types[$type]); } } } // Don't show an option to change to the current status, or to change to // the duplicate status explicitly. unset($resolution_types[$task->getStatus()]); unset($resolution_types[ManiphestTaskStatus::getDuplicateStatus()]); // Don't show owner/priority changes for closed tasks, as they don't make // much sense. if ($task->isClosed()) { unset($transaction_types[ManiphestTransaction::TYPE_PRIORITY]); unset($transaction_types[ManiphestTransaction::TYPE_OWNER]); } $default_claim = array($user->getPHID() => $user->getUsername() . ' (' . $user->getRealName() . ')'); $draft = id(new PhabricatorDraft())->loadOneWhere('authorPHID = %s AND draftKey = %s', $user->getPHID(), $task->getPHID()); if ($draft) { $draft_text = $draft->getDraft(); } else { $draft_text = null; } $projects_source = new PhabricatorProjectDatasource(); $users_source = new PhabricatorPeopleDatasource(); $mailable_source = new PhabricatorMetaMTAMailableDatasource(); $comment_form = new AphrontFormView(); $comment_form->setUser($user)->setWorkflow(true)->setAction('/maniphest/transaction/save/')->setEncType('multipart/form-data')->addHiddenInput('taskID', $task->getID())->appendChild(id(new AphrontFormSelectControl())->setLabel(pht('Action'))->setName('action')->setOptions($transaction_types)->setID('transaction-action'))->appendChild(id(new AphrontFormSelectControl())->setLabel(pht('Status'))->setName('resolution')->setControlID('resolution')->setControlStyle('display: none')->setOptions($resolution_types))->appendControl(id(new AphrontFormTokenizerControl())->setLabel(pht('Assign To'))->setName('assign_to')->setControlID('assign_to')->setControlStyle('display: none')->setID('assign-tokenizer')->setDisableBehavior(true)->setDatasource($users_source))->appendControl(id(new AphrontFormTokenizerControl())->setLabel(pht('CCs'))->setName('ccs')->setControlID('ccs')->setControlStyle('display: none')->setID('cc-tokenizer')->setDisableBehavior(true)->setDatasource($mailable_source))->appendChild(id(new AphrontFormSelectControl())->setLabel(pht('Priority'))->setName('priority')->setOptions($priority_map)->setControlID('priority')->setControlStyle('display: none')->setValue($task->getPriority()))->appendControl(id(new AphrontFormTokenizerControl())->setLabel(pht('Projects'))->setName('projects')->setControlID('projects')->setControlStyle('display: none')->setID('projects-tokenizer')->setDisableBehavior(true)->setDatasource($projects_source))->appendChild(id(new AphrontFormFileControl())->setLabel(pht('File'))->setName('file')->setControlID('file')->setControlStyle('display: none'))->appendChild(id(new PhabricatorRemarkupControl())->setUser($user)->setLabel(pht('Comments'))->setName('comments')->setValue($draft_text)->setID('transaction-comments')->setUser($user))->appendChild(id(new AphrontFormSubmitControl())->setValue(pht('Submit'))); $control_map = array(ManiphestTransaction::TYPE_STATUS => 'resolution', ManiphestTransaction::TYPE_OWNER => 'assign_to', PhabricatorTransactions::TYPE_SUBSCRIBERS => 'ccs', ManiphestTransaction::TYPE_PRIORITY => 'priority', PhabricatorTransactions::TYPE_EDGE => 'projects'); $tokenizer_map = array(PhabricatorTransactions::TYPE_EDGE => array('id' => 'projects-tokenizer', 'src' => $projects_source->getDatasourceURI(), 'placeholder' => $projects_source->getPlaceholderText()), ManiphestTransaction::TYPE_OWNER => array('id' => 'assign-tokenizer', 'src' => $users_source->getDatasourceURI(), 'value' => $default_claim, 'limit' => 1, 'placeholder' => $users_source->getPlaceholderText()), PhabricatorTransactions::TYPE_SUBSCRIBERS => array('id' => 'cc-tokenizer', 'src' => $mailable_source->getDatasourceURI(), 'placeholder' => $mailable_source->getPlaceholderText())); // TODO: Initializing these behaviors for logged out users fatals things. if ($user->isLoggedIn()) { Javelin::initBehavior('maniphest-transaction-controls', array('select' => 'transaction-action', 'controlMap' => $control_map, 'tokenizers' => $tokenizer_map)); Javelin::initBehavior('maniphest-transaction-preview', array('uri' => '/maniphest/transaction/preview/' . $task->getID() . '/', 'preview' => 'transaction-preview', 'comments' => 'transaction-comments', 'action' => 'transaction-action', 'map' => $control_map, 'tokenizers' => $tokenizer_map)); } $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); $comment_header = $is_serious ? pht('Add Comment') : pht('Weigh In'); $preview_panel = phutil_tag_div('aphront-panel-preview', phutil_tag('div', array('id' => 'transaction-preview'), phutil_tag_div('aphront-panel-preview-loading-text', pht('Loading preview...')))); $object_name = 'T' . $task->getID(); $actions = $this->buildActionView($task); $crumbs = $this->buildApplicationCrumbs()->addTextCrumb($object_name, '/' . $object_name); $header = $this->buildHeaderView($task); $properties = $this->buildPropertyView($task, $field_list, $edges, $actions, $handles); $description = $this->buildDescriptionView($task, $engine); if (!$user->isLoggedIn()) { // TODO: Eventually, everything should run through this. For now, we're // only using it to get a consistent "Login to Comment" button. $comment_box = id(new PhabricatorApplicationTransactionCommentView())->setUser($user)->setRequestURI($request->getRequestURI()); $preview_panel = null; } else { $comment_box = id(new PHUIObjectBoxView())->setFlush(true)->setHeaderText($comment_header)->appendChild($comment_form); $timeline->setQuoteTargetID('transaction-comments'); $timeline->setQuoteRef($object_name); } $object_box = id(new PHUIObjectBoxView())->setHeader($header)->addPropertyList($properties); if ($info_view) { $object_box->setInfoView($info_view); } if ($description) { $object_box->addPropertyList($description); } return $this->buildApplicationPage(array($crumbs, $object_box, $timeline, $comment_box, $preview_panel), array('title' => 'T' . $task->getID() . ' ' . $task->getTitle(), 'pageObjects' => array($task->getPHID()))); }
public function generateTaskPriority() { return array_rand(ManiphestTaskPriority::getTaskPriorityMap()); }
/** * @phutil-external-symbol class PHPExcel * @phutil-external-symbol class PHPExcel_IOFactory * @phutil-external-symbol class PHPExcel_Style_NumberFormat */ public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $ok = @(include_once 'PHPExcel.php'); if (!$ok) { $dialog = new AphrontDialogView(); $dialog->setUser($user); $dialog->setTitle('Excel Export Not Configured'); $dialog->appendChild('<p>This system does not have PHPExcel installed. This software ' . 'component is required to export tasks to Excel. Have your system ' . 'administrator install it from:</p>' . '<br />' . '<p>' . '<a href="http://www.phpexcel.net/">http://www.phpexcel.net/</a>' . '</p>' . '<br />' . '<p>Your PHP "include_path" needs to be updated to include the ' . 'PHPExcel Classes/ directory.</p>'); $dialog->addCancelButton('/maniphest/'); return id(new AphrontDialogResponse())->setDialog($dialog); } $query = id(new PhabricatorSearchQuery())->loadOneWhere('queryKey = %s', $this->key); if (!$query) { return new Aphront404Response(); } if (!$request->isDialogFormPost()) { $dialog = new AphrontDialogView(); $dialog->setUser($user); $dialog->setTitle('Export Tasks to Excel'); $dialog->appendChild('<p>Do you want to export the query results to Excel?</p>'); $dialog->addCancelButton('/maniphest/'); $dialog->addSubmitButton('Export to Excel'); return id(new AphrontDialogResponse())->setDialog($dialog); } $query->setParameter('limit', null); $query->setParameter('offset', null); $query->setParameter('order', 'p'); $query->setParameter('group', 'n'); list($tasks, $handles) = ManiphestTaskListController::loadTasks($query); // Ungroup tasks. $tasks = array_mergev($tasks); $all_projects = array_mergev(mpull($tasks, 'getProjectPHIDs')); $project_handles = $this->loadViewerHandles($all_projects); $handles += $project_handles; $workbook = new PHPExcel(); $sheet = $workbook->setActiveSheetIndex(0); $sheet->setTitle('Tasks'); $widths = array(null, 15, null, 10, 15, 15, 60, 30, 20, 100); 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('ID', 'Owner', 'Status', 'Priority', 'Date Created', 'Date Updated', 'Title', 'Projects', 'URI', 'Description'); $is_date = array(false, false, false, false, true, true, false, false, false, false); $header_format = array('font' => array('bold' => true)); foreach ($tasks as $task) { $task_owner = null; if ($task->getOwnerPHID()) { $task_owner = $handles[$task->getOwnerPHID()]->getName(); } $projects = array(); foreach ($task->getProjectPHIDs() as $phid) { $projects[] = $handles[$phid]->getName(); } $projects = implode(', ', $projects); $rows[] = array('T' . $task->getID(), $task_owner, idx($status_map, $task->getStatus(), '?'), idx($pri_map, $task->getPriority(), '?'), $this->computeExcelDate($task->getDateCreated()), $this->computeExcelDate($task->getDateModified()), $task->getTitle(), $projects, PhabricatorEnv::getProductionURI('/T' . $task->getID()), phutil_utf8_shorten($task->getDescription(), 512)); } foreach ($rows as $row => $cols) { foreach ($cols as $col => $spec) { $cell_name = $this->col($col) . ($row + 1); $sheet->setCellValue($cell_name, $spec); if ($row == 0) { $sheet->getStyle($cell_name)->applyFromArray($header_format); } if ($is_date[$col]) { $code = PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD2; $sheet->getStyle($cell_name)->getNumberFormat()->setFormatCode($code); } } } $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('maniphest_tasks_' . date('Ymd') . '.xlsx')->setContent($data); }
private function getTaskPriorityMap(ManiphestTask $task) { $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); $current_priority = $task->getPriority(); // If the current value isn't a legitimate one, put it in the dropdown // anyway so saving the form doesn't cause a side effects. if (idx($priority_map, $current_priority) === null) { $priority_map[$current_priority] = pht('<Unknown: %s>', $current_priority); } foreach ($priority_map as $priority => $priority_name) { // Always keep the current priority. if ($priority == $current_priority) { continue; } if (ManiphestTaskPriority::isDisabledPriority($priority)) { unset($priority_map[$priority]); continue; } } return $priority_map; }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $e_title = null; $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); $task = id(new ManiphestTask())->load($this->id); if (!$task) { return new Aphront404Response(); } $transactions = id(new ManiphestTransaction())->loadAllWhere('taskID = %d ORDER BY id ASC', $task->getID()); $phids = array(); foreach ($transactions as $transaction) { foreach ($transaction->extractPHIDs() as $phid) { $phids[$phid] = true; } } foreach ($task->getCCPHIDs() as $phid) { $phids[$phid] = true; } foreach ($task->getProjectPHIDs() as $phid) { $phids[$phid] = true; } if ($task->getOwnerPHID()) { $phids[$task->getOwnerPHID()] = true; } $phids[$task->getAuthorPHID()] = true; $phids = array_keys($phids); $attached = $task->getAttached(); foreach ($attached as $type => $list) { foreach ($list as $phid => $info) { $phids[$phid] = true; } } $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles(); $engine = PhabricatorMarkupEngine::newManiphestMarkupEngine(); $dict = array(); $dict['Status'] = '<strong>' . ManiphestTaskStatus::getTaskStatusFullName($task->getStatus()) . '</strong>'; $dict['Assigned To'] = $task->getOwnerPHID() ? $handles[$task->getOwnerPHID()]->renderLink() : '<em>None</em>'; $dict['Priority'] = ManiphestTaskPriority::getTaskPriorityName($task->getPriority()); $cc = $task->getCCPHIDs(); if ($cc) { $cc_links = array(); foreach ($cc as $phid) { $cc_links[] = $handles[$phid]->renderLink(); } $dict['CC'] = implode(', ', $cc_links); } else { $dict['CC'] = '<em>None</em>'; } $dict['Author'] = $handles[$task->getAuthorPHID()]->renderLink(); $projects = $task->getProjectPHIDs(); if ($projects) { $project_links = array(); foreach ($projects as $phid) { $project_links[] = $handles[$phid]->renderLink(); } $dict['Projects'] = implode(', ', $project_links); } else { $dict['Projects'] = '<em>None</em>'; } if (idx($attached, PhabricatorPHIDConstants::PHID_TYPE_DREV)) { $revs = idx($attached, PhabricatorPHIDConstants::PHID_TYPE_DREV); $rev_links = array(); foreach ($revs as $rev => $info) { $rev_links[] = $handles[$rev]->renderLink(); } $rev_links = implode('<br />', $rev_links); $dict['Revisions'] = $rev_links; } if (idx($attached, PhabricatorPHIDConstants::PHID_TYPE_FILE)) { $file_infos = idx($attached, PhabricatorPHIDConstants::PHID_TYPE_FILE); $file_phids = array_keys($file_infos); if ($file_phids) { $files = id(new PhabricatorFile())->loadAllWhere('phid IN (%Ls)', $file_phids); $views = array(); foreach ($files as $file) { $view = new AphrontFilePreviewView(); $view->setFile($file); $views[] = $view->render(); } $dict['Files'] = implode('', $views); } } $dict['Description'] = '<div class="maniphest-task-description">' . '<div class="phabricator-remarkup">' . $engine->markupText($task->getDescription()) . '</div>' . '</div>'; require_celerity_resource('mainphest-task-detail-css'); $table = array(); foreach ($dict as $key => $value) { $table[] = '<tr>' . '<th>' . phutil_escape_html($key) . ':</th>' . '<td>' . $value . '</td>' . '</tr>'; } $table = '<table class="maniphest-task-properties">' . implode("\n", $table) . '</table>'; $actions = array(); $action = new AphrontHeadsupActionView(); $action->setName('Edit Task'); $action->setURI('/maniphest/task/edit/' . $task->getID() . '/'); $action->setClass('action-edit'); $actions[] = $action; require_celerity_resource('phabricator-object-selector-css'); require_celerity_resource('javelin-behavior-phabricator-object-selector'); $action = new AphrontHeadsupActionView(); $action->setName('Merge Duplicates'); $action->setURI('/search/attach/' . $task->getPHID() . '/TASK/merge/'); $action->setWorkflow(true); $action->setClass('action-merge'); $actions[] = $action; $action = new AphrontHeadsupActionView(); $action->setName('Edit Differential Revisions'); $action->setURI('/search/attach/' . $task->getPHID() . '/DREV/'); $action->setWorkflow(true); $action->setClass('action-attach'); $actions[] = $action; $action_list = new AphrontHeadsupActionListView(); $action_list->setActions($actions); $panel = '<div class="maniphest-panel">' . $action_list->render() . '<div class="maniphest-task-detail-core">' . '<h1>' . '<span class="aphront-headsup-object-name">' . phutil_escape_html('T' . $task->getID()) . '</span>' . ' ' . phutil_escape_html($task->getTitle()) . '</h1>' . $table . '</div>' . '</div>'; $transaction_types = ManiphestTransactionType::getTransactionTypeMap(); $resolution_types = ManiphestTaskStatus::getTaskStatusMap(); if ($task->getStatus() == ManiphestTaskStatus::STATUS_OPEN) { $resolution_types = array_select_keys($resolution_types, array(ManiphestTaskStatus::STATUS_CLOSED_RESOLVED, ManiphestTaskStatus::STATUS_CLOSED_WONTFIX, ManiphestTaskStatus::STATUS_CLOSED_INVALID, ManiphestTaskStatus::STATUS_CLOSED_SPITE)); } else { $resolution_types = array(ManiphestTaskStatus::STATUS_OPEN => 'Reopened'); $transaction_types[ManiphestTransactionType::TYPE_STATUS] = 'Reopen Task'; unset($transaction_types[ManiphestTransactionType::TYPE_PRIORITY]); unset($transaction_types[ManiphestTransactionType::TYPE_OWNER]); } $default_claim = array($user->getPHID() => $user->getUsername() . ' (' . $user->getRealName() . ')'); $draft = id(new PhabricatorDraft())->loadOneWhere('authorPHID = %s AND draftKey = %s', $user->getPHID(), $task->getPHID()); if ($draft) { $draft_text = $draft->getDraft(); } else { $draft_text = null; } $panel_id = celerity_generate_unique_node_id(); $comment_form = new AphrontFormView(); $comment_form->setUser($user)->setAction('/maniphest/transaction/save/')->setEncType('multipart/form-data')->addHiddenInput('taskID', $task->getID())->appendChild(id(new AphrontFormSelectControl())->setLabel('Action')->setName('action')->setOptions($transaction_types)->setID('transaction-action'))->appendChild(id(new AphrontFormSelectControl())->setLabel('Resolution')->setName('resolution')->setControlID('resolution')->setControlStyle('display: none')->setOptions($resolution_types))->appendChild(id(new AphrontFormTokenizerControl())->setLabel('Assign To')->setName('assign_to')->setControlID('assign_to')->setControlStyle('display: none')->setID('assign-tokenizer')->setDisableBehavior(true))->appendChild(id(new AphrontFormTokenizerControl())->setLabel('CCs')->setName('ccs')->setControlID('ccs')->setControlStyle('display: none')->setID('cc-tokenizer')->setDisableBehavior(true))->appendChild(id(new AphrontFormSelectControl())->setLabel('Priority')->setName('priority')->setOptions($priority_map)->setControlID('priority')->setControlStyle('display: none')->setValue($task->getPriority()))->appendChild(id(new AphrontFormTokenizerControl())->setLabel('Projects')->setName('projects')->setControlID('projects')->setControlStyle('display: none')->setID('projects-tokenizer')->setDisableBehavior(true))->appendChild(id(new AphrontFormFileControl())->setLabel('File')->setName('file')->setControlID('file')->setControlStyle('display: none'))->appendChild(id(new AphrontFormTextAreaControl())->setLabel('Comments')->setName('comments')->setValue($draft_text)->setID('transaction-comments'))->appendChild(id(new AphrontFormDragAndDropUploadControl())->setLabel('Attached Files')->setName('files')->setDragAndDropTarget($panel_id)->setActivatedClass('aphront-panel-view-drag-and-drop'))->appendChild(id(new AphrontFormSubmitControl())->setValue('Avast!')); $control_map = array(ManiphestTransactionType::TYPE_STATUS => 'resolution', ManiphestTransactionType::TYPE_OWNER => 'assign_to', ManiphestTransactionType::TYPE_CCS => 'ccs', ManiphestTransactionType::TYPE_PRIORITY => 'priority', ManiphestTransactionType::TYPE_PROJECTS => 'projects', ManiphestTransactionType::TYPE_ATTACH => 'file'); Javelin::initBehavior('maniphest-transaction-controls', array('select' => 'transaction-action', 'controlMap' => $control_map, 'tokenizers' => array(ManiphestTransactionType::TYPE_PROJECTS => array('id' => 'projects-tokenizer', 'src' => '/typeahead/common/projects/'), ManiphestTransactionType::TYPE_OWNER => array('id' => 'assign-tokenizer', 'src' => '/typeahead/common/users/', 'value' => $default_claim, 'limit' => 1), ManiphestTransactionType::TYPE_CCS => array('id' => 'cc-tokenizer', 'src' => '/typeahead/common/mailable/')))); Javelin::initBehavior('maniphest-transaction-preview', array('uri' => '/maniphest/transaction/preview/' . $task->getID() . '/', 'preview' => 'transaction-preview', 'comments' => 'transaction-comments', 'action' => 'transaction-action', 'map' => $control_map)); $comment_panel = new AphrontPanelView(); $comment_panel->appendChild($comment_form); $comment_panel->setID($panel_id); $comment_panel->addClass('aphront-panel-accent'); $comment_panel->setHeader('Weigh In'); $preview_panel = '<div class="aphront-panel-preview"> <div id="transaction-preview"> <div class="aphront-panel-preview-loading-text"> Loading preview... </div> </div> </div>'; $transaction_view = new ManiphestTransactionListView(); $transaction_view->setTransactions($transactions); $transaction_view->setHandles($handles); $transaction_view->setUser($user); $transaction_view->setMarkupEngine($engine); return $this->buildStandardPageResponse(array($panel, $transaction_view, $comment_panel, $preview_panel), array('title' => 'T' . $task->getID() . ' ' . $task->getTitle())); }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $e_title = null; $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); $task = id(new ManiphestTask())->load($this->id); if (!$task) { return new Aphront404Response(); } $workflow = $request->getStr('workflow'); $parent_task = null; if ($workflow && is_numeric($workflow)) { $parent_task = id(new ManiphestTask())->load($workflow); } $transactions = id(new ManiphestTransaction())->loadAllWhere('taskID = %d ORDER BY id ASC', $task->getID()); $phids = array(); foreach ($transactions as $transaction) { foreach ($transaction->extractPHIDs() as $phid) { $phids[$phid] = true; } } foreach ($task->getCCPHIDs() as $phid) { $phids[$phid] = true; } foreach ($task->getProjectPHIDs() as $phid) { $phids[$phid] = true; } if ($task->getOwnerPHID()) { $phids[$task->getOwnerPHID()] = true; } $phids[$task->getAuthorPHID()] = true; $attached = $task->getAttached(); foreach ($attached as $type => $list) { foreach ($list as $phid => $info) { $phids[$phid] = true; } } if ($parent_task) { $phids[$parent_task->getPHID()] = true; } $phids = array_keys($phids); $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles(); $engine = PhabricatorMarkupEngine::newManiphestMarkupEngine(); $dict = array(); $dict['Status'] = '<strong>' . ManiphestTaskStatus::getTaskStatusFullName($task->getStatus()) . '</strong>'; $dict['Assigned To'] = $task->getOwnerPHID() ? $handles[$task->getOwnerPHID()]->renderLink() : '<em>None</em>'; $dict['Priority'] = ManiphestTaskPriority::getTaskPriorityName($task->getPriority()); $cc = $task->getCCPHIDs(); if ($cc) { $cc_links = array(); foreach ($cc as $phid) { $cc_links[] = $handles[$phid]->renderLink(); } $dict['CC'] = implode(', ', $cc_links); } else { $dict['CC'] = '<em>None</em>'; } $dict['Author'] = $handles[$task->getAuthorPHID()]->renderLink(); $source = $task->getOriginalEmailSource(); if ($source) { $subject = '[T' . $task->getID() . '] ' . $task->getTitle(); $dict['From Email'] = phutil_render_tag('a', array('href' => 'mailto:' . $source . '?subject=' . $subject), phutil_escape_html($source)); } $projects = $task->getProjectPHIDs(); if ($projects) { $project_links = array(); foreach ($projects as $phid) { $project_links[] = $handles[$phid]->renderLink(); } $dict['Projects'] = implode(', ', $project_links); } else { $dict['Projects'] = '<em>None</em>'; } $extensions = ManiphestTaskExtensions::newExtensions(); $aux_fields = $extensions->getAuxiliaryFieldSpecifications(); if ($aux_fields) { $task->loadAndAttachAuxiliaryAttributes(); foreach ($aux_fields as $aux_field) { $aux_key = $aux_field->getAuxiliaryKey(); $aux_field->setValue($task->getAuxiliaryAttribute($aux_key)); $value = $aux_field->renderForDetailView(); if (strlen($value)) { $dict[$aux_field->getLabel()] = $value; } } } $dtasks = idx($attached, PhabricatorPHIDConstants::PHID_TYPE_TASK); if ($dtasks) { $dtask_links = array(); foreach ($dtasks as $dtask => $info) { $dtask_links[] = $handles[$dtask]->renderLink(); } $dtask_links = implode('<br />', $dtask_links); $dict['Depends On'] = $dtask_links; } $revs = idx($attached, PhabricatorPHIDConstants::PHID_TYPE_DREV); if ($revs) { $rev_links = array(); foreach ($revs as $rev => $info) { $rev_links[] = $handles[$rev]->renderLink(); } $rev_links = implode('<br />', $rev_links); $dict['Revisions'] = $rev_links; } $file_infos = idx($attached, PhabricatorPHIDConstants::PHID_TYPE_FILE); if ($file_infos) { $file_phids = array_keys($file_infos); $files = id(new PhabricatorFile())->loadAllWhere('phid IN (%Ls)', $file_phids); $views = array(); foreach ($files as $file) { $view = new AphrontFilePreviewView(); $view->setFile($file); $views[] = $view->render(); } $dict['Files'] = implode('', $views); } $dict['Description'] = '<div class="maniphest-task-description">' . '<div class="phabricator-remarkup">' . $engine->markupText($task->getDescription()) . '</div>' . '</div>'; require_celerity_resource('mainphest-task-detail-css'); $table = array(); foreach ($dict as $key => $value) { $table[] = '<tr>' . '<th>' . phutil_escape_html($key) . ':</th>' . '<td>' . $value . '</td>' . '</tr>'; } $table = '<table class="maniphest-task-properties">' . implode("\n", $table) . '</table>'; $context_bar = null; if ($parent_task) { $context_bar = new AphrontContextBarView(); $context_bar->addButton(phutil_render_tag('a', array('href' => '/maniphest/task/create/?parent=' . $parent_task->getID(), 'class' => 'green button'), 'Create Another Subtask')); $context_bar->appendChild('Created a subtask of <strong>' . $handles[$parent_task->getPHID()]->renderLink() . '</strong>'); } else { if ($workflow == 'create') { $context_bar = new AphrontContextBarView(); $context_bar->addButton(phutil_render_tag('a', array('href' => '/maniphest/task/create/?template=' . $task->getID(), 'class' => 'green button'), 'Create Another Task')); $context_bar->appendChild('New task created.'); } } $actions = array(); $action = new AphrontHeadsupActionView(); $action->setName('Edit Task'); $action->setURI('/maniphest/task/edit/' . $task->getID() . '/'); $action->setClass('action-edit'); $actions[] = $action; require_celerity_resource('phabricator-object-selector-css'); require_celerity_resource('javelin-behavior-phabricator-object-selector'); $action = new AphrontHeadsupActionView(); $action->setName('Merge Duplicates'); $action->setURI('/search/attach/' . $task->getPHID() . '/TASK/merge/'); $action->setWorkflow(true); $action->setClass('action-merge'); $actions[] = $action; $action = new AphrontHeadsupActionView(); $action->setName('Create Subtask'); $action->setURI('/maniphest/task/create/?parent=' . $task->getID()); $action->setClass('action-branch'); $actions[] = $action; $action = new AphrontHeadsupActionView(); $action->setName('Edit Dependencies'); $action->setURI('/search/attach/' . $task->getPHID() . '/TASK/dependencies/'); $action->setWorkflow(true); $action->setClass('action-dependencies'); $actions[] = $action; $action = new AphrontHeadsupActionView(); $action->setName('Edit Differential Revisions'); $action->setURI('/search/attach/' . $task->getPHID() . '/DREV/'); $action->setWorkflow(true); $action->setClass('action-attach'); $actions[] = $action; $action_list = new AphrontHeadsupActionListView(); $action_list->setActions($actions); $panel = '<div class="maniphest-panel">' . $action_list->render() . '<div class="maniphest-task-detail-core">' . '<h1>' . '<span class="aphront-headsup-object-name">' . phutil_escape_html('T' . $task->getID()) . '</span>' . ' ' . phutil_escape_html($task->getTitle()) . '</h1>' . $table . '</div>' . '</div>'; $transaction_types = ManiphestTransactionType::getTransactionTypeMap(); $resolution_types = ManiphestTaskStatus::getTaskStatusMap(); if ($task->getStatus() == ManiphestTaskStatus::STATUS_OPEN) { $resolution_types = array_select_keys($resolution_types, array(ManiphestTaskStatus::STATUS_CLOSED_RESOLVED, ManiphestTaskStatus::STATUS_CLOSED_WONTFIX, ManiphestTaskStatus::STATUS_CLOSED_INVALID, ManiphestTaskStatus::STATUS_CLOSED_SPITE)); } else { $resolution_types = array(ManiphestTaskStatus::STATUS_OPEN => 'Reopened'); $transaction_types[ManiphestTransactionType::TYPE_STATUS] = 'Reopen Task'; unset($transaction_types[ManiphestTransactionType::TYPE_PRIORITY]); unset($transaction_types[ManiphestTransactionType::TYPE_OWNER]); } $default_claim = array($user->getPHID() => $user->getUsername() . ' (' . $user->getRealName() . ')'); $draft = id(new PhabricatorDraft())->loadOneWhere('authorPHID = %s AND draftKey = %s', $user->getPHID(), $task->getPHID()); if ($draft) { $draft_text = $draft->getDraft(); } else { $draft_text = null; } $panel_id = celerity_generate_unique_node_id(); $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); if ($is_serious) { // Prevent tasks from being closed "out of spite" in serious business // installs. unset($resolution_types[ManiphestTaskStatus::STATUS_CLOSED_SPITE]); } $remarkup_href = PhabricatorEnv::getDoclink('article/Remarkup_Reference.html'); $comment_form = new AphrontFormView(); $comment_form->setUser($user)->setAction('/maniphest/transaction/save/')->setEncType('multipart/form-data')->addHiddenInput('taskID', $task->getID())->appendChild(id(new AphrontFormSelectControl())->setLabel('Action')->setName('action')->setOptions($transaction_types)->setID('transaction-action'))->appendChild(id(new AphrontFormSelectControl())->setLabel('Resolution')->setName('resolution')->setControlID('resolution')->setControlStyle('display: none')->setOptions($resolution_types))->appendChild(id(new AphrontFormTokenizerControl())->setLabel('Assign To')->setName('assign_to')->setControlID('assign_to')->setControlStyle('display: none')->setID('assign-tokenizer')->setDisableBehavior(true))->appendChild(id(new AphrontFormTokenizerControl())->setLabel('CCs')->setName('ccs')->setControlID('ccs')->setControlStyle('display: none')->setID('cc-tokenizer')->setDisableBehavior(true))->appendChild(id(new AphrontFormSelectControl())->setLabel('Priority')->setName('priority')->setOptions($priority_map)->setControlID('priority')->setControlStyle('display: none')->setValue($task->getPriority()))->appendChild(id(new AphrontFormTokenizerControl())->setLabel('Projects')->setName('projects')->setControlID('projects')->setControlStyle('display: none')->setID('projects-tokenizer')->setDisableBehavior(true))->appendChild(id(new AphrontFormFileControl())->setLabel('File')->setName('file')->setControlID('file')->setControlStyle('display: none'))->appendChild(id(new AphrontFormTextAreaControl())->setLabel('Comments')->setName('comments')->setValue($draft_text)->setCaption(phutil_render_tag('a', array('href' => $remarkup_href, 'tabindex' => '-1', 'target' => '_blank'), 'Formatting Reference'))->setID('transaction-comments'))->appendChild(id(new AphrontFormDragAndDropUploadControl())->setLabel('Attached Files')->setName('files')->setDragAndDropTarget($panel_id)->setActivatedClass('aphront-panel-view-drag-and-drop'))->appendChild(id(new AphrontFormSubmitControl())->setValue($is_serious ? 'Submit' : 'Avast!')); $control_map = array(ManiphestTransactionType::TYPE_STATUS => 'resolution', ManiphestTransactionType::TYPE_OWNER => 'assign_to', ManiphestTransactionType::TYPE_CCS => 'ccs', ManiphestTransactionType::TYPE_PRIORITY => 'priority', ManiphestTransactionType::TYPE_PROJECTS => 'projects', ManiphestTransactionType::TYPE_ATTACH => 'file'); Javelin::initBehavior('maniphest-transaction-controls', array('select' => 'transaction-action', 'controlMap' => $control_map, 'tokenizers' => array(ManiphestTransactionType::TYPE_PROJECTS => array('id' => 'projects-tokenizer', 'src' => '/typeahead/common/projects/', 'ondemand' => PhabricatorEnv::getEnvConfig('tokenizer.ondemand')), ManiphestTransactionType::TYPE_OWNER => array('id' => 'assign-tokenizer', 'src' => '/typeahead/common/users/', 'value' => $default_claim, 'limit' => 1, 'ondemand' => PhabricatorEnv::getEnvConfig('tokenizer.ondemand')), ManiphestTransactionType::TYPE_CCS => array('id' => 'cc-tokenizer', 'src' => '/typeahead/common/mailable/', 'ondemand' => PhabricatorEnv::getEnvConfig('tokenizer.ondemand'))))); Javelin::initBehavior('maniphest-transaction-preview', array('uri' => '/maniphest/transaction/preview/' . $task->getID() . '/', 'preview' => 'transaction-preview', 'comments' => 'transaction-comments', 'action' => 'transaction-action', 'map' => $control_map)); $comment_panel = new AphrontPanelView(); $comment_panel->appendChild($comment_form); $comment_panel->setID($panel_id); $comment_panel->addClass('aphront-panel-accent'); $comment_panel->setHeader($is_serious ? 'Add Comment' : 'Weigh In'); $preview_panel = '<div class="aphront-panel-preview"> <div id="transaction-preview"> <div class="aphront-panel-preview-loading-text"> Loading preview... </div> </div> </div>'; $transaction_view = new ManiphestTransactionListView(); $transaction_view->setTransactions($transactions); $transaction_view->setHandles($handles); $transaction_view->setUser($user); $transaction_view->setMarkupEngine($engine); return $this->buildStandardPageResponse(array($context_bar, $panel, $transaction_view, $comment_panel, $preview_panel), array('title' => 'T' . $task->getID() . ' ' . $task->getTitle())); }
} $data = json_decode($data['parameters'], true); if (!is_array($data)) { echo "Unable to decode query data.\n"; continue; } if (idx($data, 'view') != 'custom') { echo "Query is not a custom query.\n"; continue; } $new_data = array('limit' => 1000); if (isset($data['lowPriority']) || isset($data['highPriority'])) { $lo = idx($data, 'lowPriority'); $hi = idx($data, 'highPriority'); $priorities = array(); $all = ManiphestTaskPriority::getTaskPriorityMap(); foreach ($all as $pri => $name) { if ($lo !== null && $pri < $lo) { continue; } if ($hi !== null && $pri > $hi) { continue; } $priorities[] = $pri; } if (count($priorities) != count($all)) { $new_data['priorities'] = $priorities; } } foreach ($data as $key => $value) { switch ($key) {
public function renderOpenTasks() { $request = $this->getRequest(); $user = $request->getUser(); $query = id(new ManiphestTaskQuery())->withStatus(ManiphestTaskQuery::STATUS_OPEN); $project_phid = $request->getStr('project'); $project_handle = null; if ($project_phid) { $phids = array($project_phid); $handles = $this->loadViewerHandles($phids); $project_handle = $handles[$project_phid]; $query->withAnyProjects($phids); } $tasks = $query->execute(); $recently_closed = $this->loadRecentlyClosedTasks(); $date = phabricator_date(time(), $user); switch ($this->view) { case 'user': $result = mgroup($tasks, 'getOwnerPHID'); $leftover = idx($result, '', array()); unset($result['']); $result_closed = mgroup($recently_closed, 'getOwnerPHID'); $leftover_closed = idx($result_closed, '', array()); unset($result_closed['']); $base_link = '/maniphest/?users='; $leftover_name = phutil_render_tag('a', array('href' => $base_link . ManiphestTaskOwner::OWNER_UP_FOR_GRABS), '<em>(Up For Grabs)</em>'); $col_header = 'User'; $header = 'Open Tasks by User and Priority (' . $date . ')'; break; case 'project': $result = array(); $leftover = array(); foreach ($tasks as $task) { $phids = $task->getProjectPHIDs(); if ($phids) { foreach ($phids as $project_phid) { $result[$project_phid][] = $task; } } else { $leftover[] = $task; } } $result_closed = array(); $leftover_closed = array(); foreach ($recently_closed as $task) { $phids = $task->getProjectPHIDs(); if ($phids) { foreach ($phids as $project_phid) { $result_closed[$project_phid][] = $task; } } else { $leftover_closed[] = $task; } } $base_link = '/maniphest/view/all/?projects='; $leftover_name = phutil_render_tag('a', array('href' => $base_link . ManiphestTaskOwner::PROJECT_NO_PROJECT), '<em>(No Project)</em>'); $col_header = 'Project'; $header = 'Open Tasks by Project and Priority (' . $date . ')'; break; } $phids = array_keys($result); $handles = $this->loadViewerHandles($phids); $handles = msort($handles, 'getName'); $order = $request->getStr('order', 'name'); list($order, $reverse) = AphrontTableView::parseSort($order); require_celerity_resource('aphront-tooltip-css'); Javelin::initBehavior('phabricator-tooltips', array()); $rows = array(); $pri_total = array(); foreach (array_merge($handles, array(null)) as $handle) { if ($handle) { if ($project_handle && $project_handle->getPHID() == $handle->getPHID()) { // If filtering by, e.g., "bugs", don't show a "bugs" group. continue; } $tasks = idx($result, $handle->getPHID(), array()); $name = phutil_render_tag('a', array('href' => $base_link . $handle->getPHID()), phutil_escape_html($handle->getName())); $closed = idx($result_closed, $handle->getPHID(), array()); } else { $tasks = $leftover; $name = $leftover_name; $closed = $leftover_closed; } $taskv = $tasks; $tasks = mgroup($tasks, 'getPriority'); $row = array(); $row[] = $name; $total = 0; foreach (ManiphestTaskPriority::getTaskPriorityMap() as $pri => $label) { $n = count(idx($tasks, $pri, array())); if ($n == 0) { $row[] = '-'; } else { $row[] = number_format($n); } $total += $n; } $row[] = number_format($total); list($link, $oldest_all) = $this->renderOldest($taskv); $row[] = $link; $normal_or_better = array(); foreach ($taskv as $id => $task) { if ($task->getPriority() < ManiphestTaskPriority::PRIORITY_NORMAL) { continue; } $normal_or_better[$id] = $task; } list($link, $oldest_pri) = $this->renderOldest($normal_or_better); $row[] = $link; if ($closed) { $task_ids = implode(',', mpull($closed, 'getID')); $row[] = phutil_render_tag('a', array('href' => '/maniphest/view/custom/?s=oc&tasks=' . $task_ids, 'target' => '_blank'), phutil_escape_html(number_format(count($closed)))); } else { $row[] = '-'; } switch ($order) { case 'total': $row['sort'] = $total; break; case 'oldest-all': $row['sort'] = $oldest_all; break; case 'oldest-pri': $row['sort'] = $oldest_pri; break; case 'closed': $row['sort'] = count($closed); break; case 'name': default: $row['sort'] = $handle ? $handle->getName() : '~'; break; } $rows[] = $row; } $rows = isort($rows, 'sort'); foreach ($rows as $k => $row) { unset($rows[$k]['sort']); } if ($reverse) { $rows = array_reverse($rows); } $cname = array($col_header); $cclass = array('pri right wide'); $pri_map = ManiphestTaskPriority::getTaskBriefPriorityMap(); foreach ($pri_map as $pri => $label) { $cname[] = $label; $cclass[] = 'n'; } $cname[] = 'Total'; $cclass[] = 'n'; $cname[] = javelin_render_tag('span', array('sigil' => 'has-tooltip', 'meta' => array('tip' => 'Oldest open task.', 'size' => 200)), 'Oldest (All)'); $cclass[] = 'n'; $cname[] = javelin_render_tag('span', array('sigil' => 'has-tooltip', 'meta' => array('tip' => 'Oldest open task, excluding those with Low or Wishlist ' . 'priority.', 'size' => 200)), 'Oldest (Pri)'); $cclass[] = 'n'; list($ignored, $window_epoch) = $this->getWindow(); $cname[] = javelin_render_tag('span', array('sigil' => 'has-tooltip', 'meta' => array('tip' => 'Closed after ' . phabricator_datetime($window_epoch, $user), 'size' => 260)), 'Recently Closed'); $cclass[] = 'n'; $table = new AphrontTableView($rows); $table->setHeaders($cname); $table->setColumnClasses($cclass); $table->makeSortable($request->getRequestURI(), 'order', $order, $reverse, array('name', null, null, null, null, null, null, 'total', 'oldest-all', 'oldest-pri', 'closed')); $panel = new AphrontPanelView(); $panel->setHeader($header); $panel->appendChild($table); $tokens = array(); if ($project_handle) { $tokens = array($project_handle->getPHID() => $project_handle->getFullName()); } $filter = $this->renderReportFilters($tokens, $has_window = true); return array($filter, $panel); }
protected function applyRequest(ManiphestTask $task, ConduitAPIRequest $request, $is_new) { $changes = array(); if ($is_new) { $task->setTitle((string) $request->getValue('title')); $task->setDescription((string) $request->getValue('description')); $changes[ManiphestTransactionType::TYPE_STATUS] = ManiphestTaskStatus::STATUS_OPEN; } else { $comments = $request->getValue('comments'); if (!$is_new && $comments !== null) { $changes[ManiphestTransactionType::TYPE_NONE] = null; } $title = $request->getValue('title'); if ($title !== null) { $changes[ManiphestTransactionType::TYPE_TITLE] = $title; } $desc = $request->getValue('description'); if ($desc !== null) { $changes[ManiphestTransactionType::TYPE_DESCRIPTION] = $desc; } $status = $request->getValue('status'); if ($status !== null) { $valid_statuses = ManiphestTaskStatus::getTaskStatusMap(); if (!isset($valid_statuses[$status])) { throw id(new ConduitException('ERR-INVALID-PARAMETER'))->setErrorDescription('Status set to invalid value.'); } $changes[ManiphestTransactionType::TYPE_STATUS] = $status; } } $priority = $request->getValue('priority'); if ($priority !== null) { $valid_priorities = ManiphestTaskPriority::getTaskPriorityMap(); if (!isset($valid_priorities[$priority])) { throw id(new ConduitException('ERR-INVALID-PARAMETER'))->setErrorDescription('Priority set to invalid value.'); } $changes[ManiphestTransactionType::TYPE_PRIORITY] = $priority; } $owner_phid = $request->getValue('ownerPHID'); if ($owner_phid !== null) { $this->validatePHIDList(array($owner_phid), PhabricatorPHIDConstants::PHID_TYPE_USER, 'ownerPHID'); $changes[ManiphestTransactionType::TYPE_OWNER] = $owner_phid; } $ccs = $request->getValue('ccPHIDs'); if ($ccs !== null) { $this->validatePHIDList($ccs, PhabricatorPHIDConstants::PHID_TYPE_USER, 'ccPHIDS'); $changes[ManiphestTransactionType::TYPE_CCS] = $ccs; } $project_phids = $request->getValue('projectPHIDs'); if ($project_phids !== null) { $this->validatePHIDList($project_phids, PhabricatorPHIDConstants::PHID_TYPE_PROJ, 'projectPHIDS'); $changes[ManiphestTransactionType::TYPE_PROJECTS] = $project_phids; } $file_phids = $request->getValue('filePHIDs'); if ($file_phids !== null) { $this->validatePHIDList($file_phids, PhabricatorPHIDConstants::PHID_TYPE_FILE, 'filePHIDS'); $file_map = array_fill_keys($file_phids, true); $attached = $task->getAttached(); $attached[PhabricatorPHIDConstants::PHID_TYPE_FILE] = $file_map; $changes[ManiphestTransactionType::TYPE_ATTACH] = $attached; } $content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_CONDUIT, array()); $template = new ManiphestTransaction(); $template->setContentSource($content_source); $template->setAuthorPHID($request->getUser()->getPHID()); $transactions = array(); foreach ($changes as $type => $value) { $transaction = clone $template; $transaction->setTransactionType($type); $transaction->setNewValue($value); if ($type == ManiphestTransactionType::TYPE_NONE) { $transaction->setComments($comments); } $transactions[] = $transaction; } $auxiliary = $request->getValue('auxiliary'); if ($auxiliary) { $task->loadAndAttachAuxiliaryAttributes(); foreach ($auxiliary as $aux_key => $aux_value) { $transaction = clone $template; $transaction->setTransactionType(ManiphestTransactionType::TYPE_AUXILIARY); $transaction->setMetadataValue('aux:key', $aux_key); $transaction->setNewValue($aux_value); $transactions[] = $transaction; } } $event = new PhabricatorEvent(PhabricatorEventType::TYPE_MANIPHEST_WILLEDITTASK, array('task' => $task, 'new' => $is_new, 'transactions' => $transactions)); $event->setUser($request->getUser()); $event->setConduitRequest($request); PhutilEventEngine::dispatchEvent($event); $task = $event->getValue('task'); $transactions = $event->getValue('transactions'); $editor = new ManiphestTransactionEditor(); $editor->applyTransactions($task, $transactions); $event = new PhabricatorEvent(PhabricatorEventType::TYPE_MANIPHEST_DIDEDITTASK, array('task' => $task, 'new' => $is_new, 'transactions' => $transactions)); $event->setUser($request->getUser()); $event->setConduitRequest($request); PhutilEventEngine::dispatchEvent($event); }