diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1504,6 +1504,7 @@ 'PhabricatorDashboardPanelRenderingEngine' => 'applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php', 'PhabricatorDashboardPanelSearchApplicationCustomField' => 'applications/dashboard/customfield/PhabricatorDashboardPanelSearchApplicationCustomField.php', 'PhabricatorDashboardPanelSearchEngine' => 'applications/dashboard/query/PhabricatorDashboardPanelSearchEngine.php', + 'PhabricatorDashboardPanelSearchProjectCustomField' => 'applications/dashboard/customfield/PhabricatorDashboardPanelSearchProjectCustomField.php', 'PhabricatorDashboardPanelSearchQueryCustomField' => 'applications/dashboard/customfield/PhabricatorDashboardPanelSearchQueryCustomField.php', 'PhabricatorDashboardPanelTabsCustomField' => 'applications/dashboard/customfield/PhabricatorDashboardPanelTabsCustomField.php', 'PhabricatorDashboardPanelTransaction' => 'applications/dashboard/storage/PhabricatorDashboardPanelTransaction.php', @@ -1513,6 +1514,7 @@ 'PhabricatorDashboardPanelTypeQuery' => 'applications/dashboard/paneltype/PhabricatorDashboardPanelTypeQuery.php', 'PhabricatorDashboardPanelTypeTabs' => 'applications/dashboard/paneltype/PhabricatorDashboardPanelTypeTabs.php', 'PhabricatorDashboardPanelTypeText' => 'applications/dashboard/paneltype/PhabricatorDashboardPanelTypeText.php', + 'PhabricatorDashboardPanelTypeWorkboard' => 'applications/dashboard/paneltype/PhabricatorDashboardPanelTypeWorkboard.php', 'PhabricatorDashboardPanelViewController' => 'applications/dashboard/controller/PhabricatorDashboardPanelViewController.php', 'PhabricatorDashboardQuery' => 'applications/dashboard/query/PhabricatorDashboardQuery.php', 'PhabricatorDashboardRemarkupRule' => 'applications/dashboard/remarkup/PhabricatorDashboardRemarkupRule.php', @@ -4338,6 +4340,7 @@ 'PhabricatorDashboardPanelRenderingEngine' => 'Phobject', 'PhabricatorDashboardPanelSearchApplicationCustomField' => 'PhabricatorStandardCustomField', 'PhabricatorDashboardPanelSearchEngine' => 'PhabricatorApplicationSearchEngine', + 'PhabricatorDashboardPanelSearchProjectCustomField' => 'PhabricatorStandardCustomField', 'PhabricatorDashboardPanelSearchQueryCustomField' => 'PhabricatorStandardCustomField', 'PhabricatorDashboardPanelTabsCustomField' => 'PhabricatorStandardCustomField', 'PhabricatorDashboardPanelTransaction' => 'PhabricatorApplicationTransaction', @@ -4347,6 +4350,7 @@ 'PhabricatorDashboardPanelTypeQuery' => 'PhabricatorDashboardPanelType', 'PhabricatorDashboardPanelTypeTabs' => 'PhabricatorDashboardPanelType', 'PhabricatorDashboardPanelTypeText' => 'PhabricatorDashboardPanelType', + 'PhabricatorDashboardPanelTypeWorkboard' => 'PhabricatorDashboardPanelType', 'PhabricatorDashboardPanelViewController' => 'PhabricatorDashboardController', 'PhabricatorDashboardQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorDashboardRemarkupRule' => 'PhabricatorRemarkupRuleObject', diff --git a/src/applications/dashboard/customfield/PhabricatorDashboardPanelSearchProjectCustomField.php b/src/applications/dashboard/customfield/PhabricatorDashboardPanelSearchProjectCustomField.php new file mode 100644 --- /dev/null +++ b/src/applications/dashboard/customfield/PhabricatorDashboardPanelSearchProjectCustomField.php @@ -0,0 +1,21 @@ +setDatasource('/typeahead/common/projects/') + ->setID($this->getFieldControlID()) + ->setLabel($this->getFieldName()) + ->setCaption($this->getCaption()) + ->setName($this->getFieldKey()) + ->setValue($this->getFieldValue()); + } + +} diff --git a/src/applications/dashboard/paneltype/PhabricatorDashboardPanelTypeWorkboard.php b/src/applications/dashboard/paneltype/PhabricatorDashboardPanelTypeWorkboard.php new file mode 100644 --- /dev/null +++ b/src/applications/dashboard/paneltype/PhabricatorDashboardPanelTypeWorkboard.php @@ -0,0 +1,163 @@ + array( + 'name' => pht('Project'), + 'type' => 'search.project', + ), + ); + } + + public function shouldRenderAsync() { + // Rendering text panels is normally a cheap cache hit. + return false; + } + + public function renderPanelContent( + PhabricatorUser $viewer, + PhabricatorDashboardPanel $panel, + PhabricatorDashboardPanelRenderingEngine $engine) { + + $project = id(new PhabricatorProjectQuery()) + ->setViewer($viewer) + ->withNames (array('RFJS')); + $project = $project->executeOne(); + + $column_query = id(new PhabricatorProjectColumnQuery()) + ->setViewer($viewer) + ->withProjectPHIDs(array($project->getPHID())); + + $columns = $column_query->execute(); + $columns = mpull($columns, null, 'getSequence'); + + // If there's no default column, create one now. + if (empty($columns[0])) { + $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); + $column = PhabricatorProjectColumn::initializeNewColumn($viewer) + ->setSequence(0) + ->setProjectPHID($project->getPHID()) + ->save(); + $column->attachProject($project); + $columns[0] = $column; + unset($unguarded); + } + + ksort($columns); + + $engine = id(new ManiphestTaskSearchEngine()) + ->setViewer($viewer) + ->setIsBoardView(true); + + $query_key = 'open'; + $saved = null; + $custom_query = null; + if ($engine->isBuiltinQuery($query_key)) { + $saved = $engine->buildSavedQueryFromBuiltin($query_key); + } + $task_query = $engine->buildQueryFromSavedQuery($saved); + + $tasks = $task_query + ->addWithAllProjects(array($project->getPHID())) + ->setOrderBy(ManiphestTaskQuery::ORDER_PRIORITY) + ->setViewer($viewer) + ->execute(); + + $tasks = mpull($tasks, null, 'getPHID'); + $task_phids = array_keys($tasks); + + if ($task_phids) { + $edge_type = PhabricatorEdgeConfig::TYPE_OBJECT_HAS_COLUMN; + $edge_query = id(new PhabricatorEdgeQuery()) + ->withSourcePHIDs($task_phids) + ->withEdgeTypes(array($edge_type)) + ->withDestinationPHIDs(mpull($columns, 'getPHID')); + $edge_query->execute(); + } + + $task_map = array(); + $default_phid = $columns[0]->getPHID(); + foreach ($tasks as $task) { + $task_phid = $task->getPHID(); + $column_phids = $edge_query->getDestinationPHIDs(array($task_phid)); + + $column_phid = head($column_phids); + $column_phid = nonempty($column_phid, $default_phid); + + $task_map[$column_phid][] = $task_phid; + } + + $board_id = celerity_generate_unique_node_id(); + $board = id(new PHUIWorkboardView()) + ->setUser($viewer) + ->setID($board_id); + + Javelin::initBehavior( + 'project-boards', + array( + 'boardID' => $board_id, + 'projectPHID' => $project->getPHID() + )); + + $handles = ManiphestTaskListView::loadTaskHandles($viewer, $tasks); + foreach ($columns as $column) { + $panel = id(new PHUIWorkpanelView()) + ->setHeader($column->getDisplayName()) + ->setHeaderColor($column->getHeaderColor()); + + $cards = id(new PHUIObjectItemListView()) + ->setUser($viewer) + ->setFlush(true) + ->setAllowEmptyList(true) + ->addSigil('project-column') + ->setMetadata( + array( + 'columnPHID' => $column->getPHID(), + )); + + $task_phids = idx($task_map, $column->getPHID(), array()); + foreach (array_select_keys($tasks, $task_phids) as $task) { + $owner = null; + if ($task->getOwnerPHID()) { + $owner = $handles[$task->getOwnerPHID()]; + } + $cards->addItem(id(new ProjectBoardTaskCard()) + ->setViewer($viewer) + ->setTask($task) + ->setOwner($owner) + ->setCanEdit(false) + ->getItem()); + } + $panel->setCards($cards); + + if (!$task_phids) { + $cards->addClass('project-column-empty'); + } + + $board->addPanel($panel); + } + + $board_box = id(new PHUIBoxView()) + ->appendChild($board) + ->addClass('project-board-wrapper'); + + return $board_box; + } + +}