diff --git a/resources/celerity/map.php b/resources/celerity/map.php --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -397,7 +397,7 @@ 'rsrc/js/application/herald/PathTypeahead.js' => 'ad486db3', 'rsrc/js/application/herald/herald-rule-editor.js' => '0922e81d', 'rsrc/js/application/maniphest/behavior-batch-selector.js' => '139ef688', - 'rsrc/js/application/maniphest/behavior-line-chart.js' => 'c8147a20', + 'rsrc/js/application/maniphest/behavior-line-chart.js' => '11167911', 'rsrc/js/application/maniphest/behavior-list-edit.js' => 'c687e867', 'rsrc/js/application/owners/OwnersPathEditor.js' => '2a8b62d9', 'rsrc/js/application/owners/owners-path-editor.js' => 'ff688a7a', @@ -625,7 +625,7 @@ 'javelin-behavior-icon-composer' => '38a6cedb', 'javelin-behavior-launch-icon-composer' => 'a17b84f1', 'javelin-behavior-lightbox-attachments' => 'c7e748bf', - 'javelin-behavior-line-chart' => 'c8147a20', + 'javelin-behavior-line-chart' => '11167911', 'javelin-behavior-linked-container' => '74446546', 'javelin-behavior-maniphest-batch-selector' => '139ef688', 'javelin-behavior-maniphest-list-editor' => 'c687e867', @@ -1007,6 +1007,12 @@ 'javelin-workflow', 'phuix-icon-view', ), + 11167911 => array( + 'javelin-behavior', + 'javelin-dom', + 'javelin-vector', + 'phui-chart-css', + ), '111bfd2d' => array( 'javelin-install', ), @@ -1997,12 +2003,6 @@ 'phuix-icon-view', 'phabricator-busy', ), - 'c8147a20' => array( - 'javelin-behavior', - 'javelin-dom', - 'javelin-vector', - 'phui-chart-css', - ), 'c9749dcd' => array( 'javelin-install', 'javelin-util', diff --git a/resources/sql/autopatches/20190416.chart.01.storage.sql b/resources/sql/autopatches/20190416.chart.01.storage.sql new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20190416.chart.01.storage.sql @@ -0,0 +1,6 @@ +CREATE TABLE {$NAMESPACE}_fact.fact_chart ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + chartKey BINARY(12) NOT NULL, + chartParameters LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT}, + UNIQUE KEY `key_chart` (chartKey) +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; 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 @@ -3201,6 +3201,7 @@ 'PhabricatorFact' => 'applications/fact/fact/PhabricatorFact.php', 'PhabricatorFactAggregate' => 'applications/fact/storage/PhabricatorFactAggregate.php', 'PhabricatorFactApplication' => 'applications/fact/application/PhabricatorFactApplication.php', + 'PhabricatorFactChart' => 'applications/fact/storage/PhabricatorFactChart.php', 'PhabricatorFactChartController' => 'applications/fact/controller/PhabricatorFactChartController.php', 'PhabricatorFactController' => 'applications/fact/controller/PhabricatorFactController.php', 'PhabricatorFactCursor' => 'applications/fact/storage/PhabricatorFactCursor.php', @@ -9229,6 +9230,10 @@ 'PhabricatorFact' => 'Phobject', 'PhabricatorFactAggregate' => 'PhabricatorFactDAO', 'PhabricatorFactApplication' => 'PhabricatorApplication', + 'PhabricatorFactChart' => array( + 'PhabricatorFactDAO', + 'PhabricatorPolicyInterface', + ), 'PhabricatorFactChartController' => 'PhabricatorFactController', 'PhabricatorFactController' => 'PhabricatorController', 'PhabricatorFactCursor' => 'PhabricatorFactDAO', diff --git a/src/applications/fact/controller/PhabricatorFactChartController.php b/src/applications/fact/controller/PhabricatorFactChartController.php --- a/src/applications/fact/controller/PhabricatorFactChartController.php +++ b/src/applications/fact/controller/PhabricatorFactChartController.php @@ -74,6 +74,8 @@ 'hardpoint' => $id, 'x' => array($x), 'y' => array($y), + 'yMax' => max(0, max($y)), + 'yMin' => min(0, min($y)), 'xformat' => 'epoch', 'colors' => array('#0000ff'), )); @@ -82,8 +84,9 @@ ->setHeaderText(pht('Count of %s', $fact->getName())) ->appendChild($chart); - $crumbs = $this->buildApplicationCrumbs(); - $crumbs->addTextCrumb(pht('Chart')); + $crumbs = $this->buildApplicationCrumbs() + ->addTextCrumb(pht('Chart')) + ->setBorder(true); $title = pht('Chart'); diff --git a/src/applications/fact/storage/PhabricatorFactChart.php b/src/applications/fact/storage/PhabricatorFactChart.php new file mode 100644 --- /dev/null +++ b/src/applications/fact/storage/PhabricatorFactChart.php @@ -0,0 +1,69 @@ + array( + 'chartParameters' => self::SERIALIZATION_JSON, + ), + self::CONFIG_COLUMN_SCHEMA => array( + 'chartKey' => 'bytes12', + ), + self::CONFIG_KEY_SCHEMA => array( + 'key_chart' => array( + 'columns' => array('chartKey'), + 'unique' => true, + ), + ), + ) + parent::getConfiguration(); + } + + public function setChartParameter($key, $value) { + $this->chartParameters[$key] = $value; + return $this; + } + + public function getChartParameter($key, $default = null) { + return idx($this->chartParameters, $key, $default); + } + + public function save() { + if ($this->getID()) { + throw new Exception( + pht( + 'Chart configurations are not mutable. You can not update or '. + 'overwrite an existing chart configuration.')); + } + + $digest = serialize($this->chartParameters); + $digest = PhabricatorHash::digestForIndex($digest); + + $this->chartKey = $digest; + + return parent::save(); + } + +/* -( PhabricatorPolicyInterface )----------------------------------------- */ + + public function getCapabilities() { + return array( + PhabricatorPolicyCapability::CAN_VIEW, + ); + } + + public function getPolicy($capability) { + return PhabricatorPolicies::getMostOpenPolicy(); + } + + public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { + return false; + } + + +} diff --git a/webroot/rsrc/js/application/maniphest/behavior-line-chart.js b/webroot/rsrc/js/application/maniphest/behavior-line-chart.js --- a/webroot/rsrc/js/application/maniphest/behavior-line-chart.js +++ b/webroot/rsrc/js/application/maniphest/behavior-line-chart.js @@ -8,7 +8,7 @@ JX.behavior('line-chart', function(config) { - function fn(n) { + function css_function(n) { return n + '(' + JX.$A(arguments).slice(1).join(', ') + ')'; } @@ -50,7 +50,7 @@ .attr('class', 'chart'); var g = svg.append('g') - .attr('transform', fn('translate', padding.left, padding.top)); + .attr('transform', css_function('translate', padding.left, padding.top)); g.append('rect') .attr('class', 'inner') @@ -73,9 +73,7 @@ x.domain(d3.extent(data, function(d) { return d.date; })); var yex = d3.extent(data, function(d) { return d.count; }); - yex[0] = 0; - yex[1] = yex[1] * 1.05; - y.domain(yex); + y.domain([config.yMin, config.yMax]); g.append('path') .datum(data) @@ -84,12 +82,12 @@ g.append('g') .attr('class', 'x axis') - .attr('transform', fn('translate', 0, size.height)) + .attr('transform', css_function('translate', 0, size.height)) .call(xAxis); g.append('g') .attr('class', 'y axis') - .attr('transform', fn('translate', 0, 0)) + .attr('transform', css_function('translate', 0, 0)) .call(yAxis); var div = d3.select('body')