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 @@ -4224,6 +4224,7 @@ 'PhabricatorProfileMenuItemView' => 'applications/search/engine/PhabricatorProfileMenuItemView.php', 'PhabricatorProfileMenuItemViewList' => 'applications/search/engine/PhabricatorProfileMenuItemViewList.php', 'PhabricatorProject' => 'applications/project/storage/PhabricatorProject.php', + 'PhabricatorProjectActivityChartEngine' => 'applications/project/chart/PhabricatorProjectActivityChartEngine.php', 'PhabricatorProjectAddHeraldAction' => 'applications/project/herald/PhabricatorProjectAddHeraldAction.php', 'PhabricatorProjectApplication' => 'applications/project/application/PhabricatorProjectApplication.php', 'PhabricatorProjectArchiveController' => 'applications/project/controller/PhabricatorProjectArchiveController.php', @@ -10733,6 +10734,7 @@ 'PhabricatorSpacesInterface', 'PhabricatorEditEngineSubtypeInterface', ), + 'PhabricatorProjectActivityChartEngine' => 'PhabricatorChartEngine', 'PhabricatorProjectAddHeraldAction' => 'PhabricatorProjectHeraldAction', 'PhabricatorProjectApplication' => 'PhabricatorApplication', 'PhabricatorProjectArchiveController' => 'PhabricatorProjectController', diff --git a/src/applications/project/chart/PhabricatorProjectActivityChartEngine.php b/src/applications/project/chart/PhabricatorProjectActivityChartEngine.php new file mode 100644 --- /dev/null +++ b/src/applications/project/chart/PhabricatorProjectActivityChartEngine.php @@ -0,0 +1,135 @@ +setEngineParameter('projectPHIDs', $project_phids); + } + + protected function newChart(PhabricatorFactChart $chart, array $map) { + $viewer = $this->getViewer(); + + $map = $map + array( + 'projectPHIDs' => array(), + ); + + if ($map['projectPHIDs']) { + $projects = id(new PhabricatorProjectQuery()) + ->setViewer($viewer) + ->withPHIDs($map['projectPHIDs']) + ->execute(); + $project_phids = mpull($projects, 'getPHID'); + } else { + $project_phids = array(); + } + + $project_phid = head($project_phids); + + $functions = array(); + $stacks = array(); + + $function = $this->newFunction( + array( + 'accumulate', + array( + 'compose', + array('fact', 'tasks.open-count.assign.project', $project_phid), + array('min', 0), + ), + )); + + $function->getFunctionLabel() + ->setKey('moved-in') + ->setName(pht('Tasks Moved Into Project')) + ->setColor('rgba(128, 128, 200, 1)') + ->setFillColor('rgba(128, 128, 200, 0.15)'); + + $functions[] = $function; + + $function = $this->newFunction( + array( + 'accumulate', + array( + 'compose', + array('fact', 'tasks.open-count.status.project', $project_phid), + array('min', 0), + ), + )); + + $function->getFunctionLabel() + ->setKey('reopened') + ->setName(pht('Tasks Reopened')) + ->setColor('rgba(128, 128, 200, 1)') + ->setFillColor('rgba(128, 128, 200, 0.15)'); + + $functions[] = $function; + + $function = $this->newFunction( + array( + 'accumulate', + array('fact', 'tasks.open-count.create.project', $project_phid), + )); + + $function->getFunctionLabel() + ->setKey('created') + ->setName(pht('Tasks Created')) + ->setColor('rgba(0, 0, 200, 1)') + ->setFillColor('rgba(0, 0, 200, 0.15)'); + + $functions[] = $function; + + $function = $this->newFunction( + array( + 'accumulate', + array( + 'compose', + array('fact', 'tasks.open-count.status.project', $project_phid), + array('max', 0), + ), + )); + + $function->getFunctionLabel() + ->setKey('closed') + ->setName(pht('Tasks Closed')) + ->setColor('rgba(0, 200, 0, 1)') + ->setFillColor('rgba(0, 200, 0, 0.15)'); + + $functions[] = $function; + + $function = $this->newFunction( + array( + 'accumulate', + array( + 'compose', + array('fact', 'tasks.open-count.assign.project', $project_phid), + array('max', 0), + ), + )); + + $function->getFunctionLabel() + ->setKey('moved-out') + ->setName(pht('Tasks Moved Out of Project')) + ->setColor('rgba(128, 200, 128, 1)') + ->setFillColor('rgba(128, 200, 128, 0.15)'); + + $functions[] = $function; + + $stacks[] = array('created', 'reopened', 'moved-in'); + $stacks[] = array('closed', 'moved-out'); + + $datasets = array(); + + $dataset = id(new PhabricatorChartStackedAreaDataset()) + ->setFunctions($functions) + ->setStacks($stacks); + + $datasets[] = $dataset; + $chart->attachDatasets($datasets); + } + +} diff --git a/src/applications/project/chart/PhabricatorProjectBurndownChartEngine.php b/src/applications/project/chart/PhabricatorProjectBurndownChartEngine.php --- a/src/applications/project/chart/PhabricatorProjectBurndownChartEngine.php +++ b/src/applications/project/chart/PhabricatorProjectBurndownChartEngine.php @@ -29,140 +29,79 @@ } $functions = array(); - $stacks = array(); - if ($project_phids) { - foreach ($project_phids as $project_phid) { - $function = $this->newFunction( - array( - 'accumulate', - array( - 'compose', - array('fact', 'tasks.open-count.assign.project', $project_phid), - array('min', 0), - ), - )); - - $function->getFunctionLabel() - ->setKey('moved-in') - ->setName(pht('Tasks Moved Into Project')) - ->setColor('rgba(128, 128, 200, 1)') - ->setFillColor('rgba(128, 128, 200, 0.15)'); - - $functions[] = $function; - - $function = $this->newFunction( - array( - 'accumulate', - array( - 'compose', - array('fact', 'tasks.open-count.status.project', $project_phid), - array('min', 0), - ), - )); - - $function->getFunctionLabel() - ->setKey('reopened') - ->setName(pht('Tasks Reopened')) - ->setColor('rgba(128, 128, 200, 1)') - ->setFillColor('rgba(128, 128, 200, 0.15)'); - - $functions[] = $function; - - $function = $this->newFunction( + $open_function = $this->newFunction( + array( + 'accumulate', array( - 'accumulate', - array('fact', 'tasks.open-count.create.project', $project_phid), - )); - - $function->getFunctionLabel() - ->setKey('created') - ->setName(pht('Tasks Created')) - ->setColor('rgba(0, 0, 200, 1)') - ->setFillColor('rgba(0, 0, 200, 0.15)'); - - $functions[] = $function; + 'sum', + $this->newFactSum( + 'tasks.open-count.create.project', $project_phids), + $this->newFactSum( + 'tasks.open-count.status.project', $project_phids), + $this->newFactSum( + 'tasks.open-count.assign.project', $project_phids), + ), + )); - $function = $this->newFunction( - array( - 'accumulate', - array( - 'compose', - array('fact', 'tasks.open-count.status.project', $project_phid), - array('max', 0), - ), - )); - - $function->getFunctionLabel() - ->setKey('closed') - ->setName(pht('Tasks Closed')) - ->setColor('rgba(0, 200, 0, 1)') - ->setFillColor('rgba(0, 200, 0, 0.15)'); - - $functions[] = $function; - - $function = $this->newFunction( - array( - 'accumulate', - array( - 'compose', - array('fact', 'tasks.open-count.assign.project', $project_phid), - array('max', 0), - ), - )); - - $function->getFunctionLabel() - ->setKey('moved-out') - ->setName(pht('Tasks Moved Out of Project')) - ->setColor('rgba(128, 200, 128, 1)') - ->setFillColor('rgba(128, 200, 128, 0.15)'); - - $functions[] = $function; - - $stacks[] = array('created', 'reopened', 'moved-in'); - $stacks[] = array('closed', 'moved-out'); - } + $closed_function = $this->newFunction( + array( + 'accumulate', + $this->newFactSum('tasks.open-count.status.project', $project_phids), + )); } else { - $function = $this->newFunction( + $open_function = $this->newFunction( array( 'accumulate', array('fact', 'tasks.open-count.create'), )); - $function->getFunctionLabel() - ->setKey('open') - ->setName(pht('Open Tasks')) - ->setColor('rgba(0, 0, 200, 1)') - ->setFillColor('rgba(0, 0, 200, 0.15)'); - - $functions[] = $function; - - $function = $this->newFunction( + $closed_function = $this->newFunction( array( 'accumulate', array('fact', 'tasks.open-count.status'), )); + } - $function->getFunctionLabel() - ->setKey('closed') - ->setName(pht('Closed Tasks')) - ->setColor('rgba(0, 200, 0, 1)') - ->setFillColor('rgba(0, 200, 0, 0.15)'); + $open_function->getFunctionLabel() + ->setKey('open') + ->setName(pht('Open Tasks')) + ->setColor('rgba(0, 0, 200, 1)') + ->setFillColor('rgba(0, 0, 200, 0.15)'); - $functions[] = $function; - } + $closed_function->getFunctionLabel() + ->setKey('closed') + ->setName(pht('Closed Tasks')) + ->setColor('rgba(0, 200, 0, 1)') + ->setFillColor('rgba(0, 200, 0, 0.15)'); $datasets = array(); $dataset = id(new PhabricatorChartStackedAreaDataset()) - ->setFunctions($functions); - - if ($stacks) { - $dataset->setStacks($stacks); - } + ->setFunctions( + array( + $open_function, + $closed_function, + )) + ->setStacks( + array( + array('open'), + array('closed'), + )); $datasets[] = $dataset; $chart->attachDatasets($datasets); } + private function newFactSum($fact_key, array $phids) { + $result = array(); + $result[] = 'sum'; + + foreach ($phids as $phid) { + $result[] = array('fact', $fact_key, $phid); + } + + return $result; + } + } diff --git a/src/applications/project/controller/PhabricatorProjectReportsController.php b/src/applications/project/controller/PhabricatorProjectReportsController.php --- a/src/applications/project/controller/PhabricatorProjectReportsController.php +++ b/src/applications/project/controller/PhabricatorProjectReportsController.php @@ -44,10 +44,24 @@ ->setParentPanelPHIDs(array()) ->renderPanel(); + $activity_panel = id(new PhabricatorProjectActivityChartEngine()) + ->setViewer($viewer) + ->setProjects(array($project)) + ->buildChartPanel(); + + $activity_panel->setName(pht('%s: Activity', $project->getName())); + + $activity_view = id(new PhabricatorDashboardPanelRenderingEngine()) + ->setViewer($viewer) + ->setPanel($activity_panel) + ->setParentPanelPHIDs(array()) + ->renderPanel(); + $view = id(new PHUITwoColumnView()) ->setFooter( array( $chart_view, + $activity_view, )); return $this->newPage()