mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-29 10:12:41 +01:00
Fix negative chart values, add storage for charts
Summary: Ref T13279. I think I'm going to fling some stuff at the wall for a bit here and hope most of it sticks, so this series of changes may not be terribly cohesive or focused. Here: The range of the chart is locked to "[0, 105% of max]". This is trying to make a pleasing extra margin above the maximum value, but currently just breaks charts with negative values. Later: - I'll probably let users customize this. - We should likely select 0 as the automatic minimum for charts with no negative values. - For charts with positive values, it would be nice to automatically pick a pleasantly round number (25, 100, 1000) as a maximum by default. We don't have any storage for charts yet. Add some. This works like queries, where every possible configuration gets a short URL slug. Nothing writes or reads this yet. Rename `fn()` to `css_function()`. This builds CSS functions for D3. The JS is likely to get substantial structural rewrites later on, `fn()` was just particularly offensive. Test Plan: Viewed a fact series with negative values. Ran `bin/storage upgrade`. Reviewers: amckinley Reviewed By: amckinley Subscribers: yelirekim, PHID-OPKG-gm6ozazyms6q6i22gyam Maniphest Tasks: T13279 Differential Revision: https://secure.phabricator.com/D20438
This commit is contained in:
parent
faf0a311ec
commit
02981f0add
6 changed files with 98 additions and 17 deletions
|
@ -397,7 +397,7 @@ return array(
|
|||
'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 @@ return array(
|
|||
'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 @@ return array(
|
|||
'javelin-workflow',
|
||||
'phuix-icon-view',
|
||||
),
|
||||
11167911 => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-vector',
|
||||
'phui-chart-css',
|
||||
),
|
||||
'111bfd2d' => array(
|
||||
'javelin-install',
|
||||
),
|
||||
|
@ -1997,12 +2003,6 @@ return array(
|
|||
'phuix-icon-view',
|
||||
'phabricator-busy',
|
||||
),
|
||||
'c8147a20' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-vector',
|
||||
'phui-chart-css',
|
||||
),
|
||||
'c9749dcd' => array(
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
|
|
6
resources/sql/autopatches/20190416.chart.01.storage.sql
Normal file
6
resources/sql/autopatches/20190416.chart.01.storage.sql
Normal file
|
@ -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};
|
|
@ -3201,6 +3201,7 @@ phutil_register_library_map(array(
|
|||
'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 @@ phutil_register_library_map(array(
|
|||
'PhabricatorFact' => 'Phobject',
|
||||
'PhabricatorFactAggregate' => 'PhabricatorFactDAO',
|
||||
'PhabricatorFactApplication' => 'PhabricatorApplication',
|
||||
'PhabricatorFactChart' => array(
|
||||
'PhabricatorFactDAO',
|
||||
'PhabricatorPolicyInterface',
|
||||
),
|
||||
'PhabricatorFactChartController' => 'PhabricatorFactController',
|
||||
'PhabricatorFactController' => 'PhabricatorController',
|
||||
'PhabricatorFactCursor' => 'PhabricatorFactDAO',
|
||||
|
|
|
@ -74,6 +74,8 @@ final class PhabricatorFactChartController extends PhabricatorFactController {
|
|||
'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 @@ final class PhabricatorFactChartController extends PhabricatorFactController {
|
|||
->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');
|
||||
|
||||
|
|
69
src/applications/fact/storage/PhabricatorFactChart.php
Normal file
69
src/applications/fact/storage/PhabricatorFactChart.php
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorFactChart
|
||||
extends PhabricatorFactDAO
|
||||
implements PhabricatorPolicyInterface {
|
||||
|
||||
protected $chartKey;
|
||||
protected $chartParameters = array();
|
||||
|
||||
protected function getConfiguration() {
|
||||
return array(
|
||||
self::CONFIG_SERIALIZATION => 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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 @@ JX.behavior('line-chart', function(config) {
|
|||
.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 @@ JX.behavior('line-chart', function(config) {
|
|||
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 @@ JX.behavior('line-chart', function(config) {
|
|||
|
||||
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')
|
||||
|
|
Loading…
Reference in a new issue