Skip to content

Commit

Permalink
Merge pull request #2 from krmorse/master
Browse files Browse the repository at this point in the history
Support aggregating by pi fields instead of plan estimate
  • Loading branch information
krmorse authored Oct 20, 2016
2 parents f53aa16 + 96c2e17 commit 69bdd40
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 21 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ App-local.html
#IDE Files
.idea
.c9revisions
node_modules
node_modules
.DS_Store
22 changes: 17 additions & 5 deletions Calculator.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@ Ext.define('Calculator', {
});
} else {
seriesData = _.map(data, function(value, key) {
var planEstimateTotal = _.reduce(value, function(total, r) {
return total + r.get('PlanEstimate');
}, 0);
return [key, planEstimateTotal];
});
var valueTotal = _.reduce(value, function(total, r) {
var valueField = this._getValueFieldForCalculationType();
return total + r.get(valueField);
}, 0, this);
return [key, valueTotal];
}, this);
}

return {
Expand All @@ -40,5 +41,16 @@ Ext.define('Calculator', {
}
]
};
},

_getValueFieldForCalculationType: function() {
switch(this.calculationType) {
case 'leafplanest':
return 'LeafStoryPlanEstimateTotal';
case 'prelimest':
return 'PreliminaryEstimateValue';
default:
return 'PlanEstimate';
}
}
});
40 changes: 37 additions & 3 deletions CustomChartApp.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Ext.define('CustomChartApp', {
},

getSettingsFields: function() {
var me = this;
return [
{
name: 'chartType',
Expand Down Expand Up @@ -139,9 +140,27 @@ Ext.define('CustomChartApp', {
fields: ['name', 'value'],
data: [
{ name: 'Count', value: 'count' },
{ name: 'Plan Estimate', value: 'estimate' }
{ name: 'Plan Estimate', value: 'estimate' },
{ name: 'Leaf Story Plan Estimate Total', value: 'leafplanest' },
{ name: 'Preliminary Estimate Value', value: 'prelimest' }
]
})
}),
handlesEvents: {
typeselected: function (types, context) {
var type = Ext.Array.from(types)[0];
Rally.data.ModelFactory.getModel({
type: type,
success: function(model) {
this.store.filterBy(function(record) {
return record.get('value') === 'count' ||
model.hasField(me._getFieldForAggregationType(record.get('value')));
});
},
scope: this
});

}
},
},
{ type: 'query' }
];
Expand Down Expand Up @@ -261,10 +280,25 @@ Ext.define('CustomChartApp', {

_getChartFetch: function() {
var field = this.getSetting('aggregationField'),
fetch = ['FormattedID', 'Name', 'PlanEstimate', field];
aggregationType = this.getSetting('aggregationType'),
fetch = ['FormattedID', 'Name', field];

if (aggregationType !== 'count') {
fetch.push(this._getFieldForAggregationType(aggregationType));
}
return fetch;
},

_getFieldForAggregationType: function(aggregationType) {
if (aggregationType === 'estimate') {
return 'PlanEstimate';
} else if (aggregationType === 'prelimest') {
return 'PreliminaryEstimateValue';
} else if (aggregationType === 'leafplanest') {
return 'LeafStoryPlanEstimateTotal';
}
},

_getChartSort: function() {
return [{
property: this.getSetting('aggregationField'),
Expand Down
4 changes: 2 additions & 2 deletions deploy/App-external.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@

<script type="text/javascript">
Rally.onReady(function () {
Ext.define("Calculator",{config:{calculationType:void 0,field:void 0},constructor:function(config){this.initConfig(config)},prepareChartData:function(store){var data=_.groupBy(store.getRange(),function(record){var value=record.get(this.field);return _.isObject(value)?value._refObjectName:value},this),categories=_.keys(data),seriesData;return seriesData="count"===this.calculationType?_.map(data,function(value,key){return[key,value.length]}):_.map(data,function(value,key){var planEstimateTotal=_.reduce(value,function(total,r){return total+r.get("PlanEstimate")},0);return[key,planEstimateTotal]}),{categories:categories,series:[{name:this.field,type:this.seriesType,data:seriesData}]}}});
Ext.define("Calculator",{config:{calculationType:void 0,field:void 0},constructor:function(config){this.initConfig(config)},prepareChartData:function(store){var data=_.groupBy(store.getRange(),function(record){var value=record.get(this.field);return _.isObject(value)?value._refObjectName:value},this),categories=_.keys(data),seriesData;return seriesData="count"===this.calculationType?_.map(data,function(value,key){return[key,value.length]}):_.map(data,function(value,key){var valueTotal=_.reduce(value,function(total,r){var valueField=this._getValueFieldForCalculationType();return total+r.get(valueField)},0,this);return[key,valueTotal]},this),{categories:categories,series:[{name:this.field,type:this.seriesType,data:seriesData}]}},_getValueFieldForCalculationType:function(){switch(this.calculationType){case"leafplanest":return"LeafStoryPlanEstimateTotal";case"prelimest":return"PreliminaryEstimateValue";default:return"PlanEstimate"}}});
Ext.define("BarCalculator",{extend:"Calculator",seriesType:"column"});
Ext.define("BarChart",{xtype:"barchart",extend:"Rally.ui.chart.Chart",requires:["BarCalculator"],chartConfig:{chart:{type:"column"},title:{text:""},tooltip:{headerFormat:"",pointFormat:"{point.name}: <b>{point.y}</b>"},yAxis:{min:0,title:{text:""},stackLabels:{enabled:!0,style:{fontWeight:"bold",color:"gray"}}},plotOptions:{column:{stacking:"normal",dataLabels:{enabled:!1},showInLegend:!1,colorByPoint:!0}}},calculatorType:"BarCalculator"});
Ext.define("PieCalculator",{extend:"Calculator",seriesType:"pie"});
Ext.define("PieChart",{xtype:"piechart",extend:"Rally.ui.chart.Chart",requires:["PieCalculator"],chartConfig:{chart:{type:"pie",plotBackgroundColor:null,plotBorderWidth:null,plotShadow:!1},title:{text:""},tooltip:{headerFormat:"",pointFormat:"{point.name}: <b>{point.percentage:.1f}%</b>"},plotOptions:{pie:{allowPointSelect:!0,cursor:"pointer",dataLabels:{enabled:!0,format:"<b>{point.name}</b>: {point.percentage:.1f} %",style:{color:"black"}}}}},calculatorType:"PieCalculator"});
Ext.define("CustomChartApp",{extend:"Rally.app.App",componentCls:"app",layout:"fit",config:{defaultSettings:{types:"defect",chartType:"piechart",aggregationField:"State",aggregationType:"count",query:""}},launch:function(){this.getSetting("types")?Rally.data.wsapi.ModelFactory.getModels({types:this._getTypesSetting()}).then({success:this._onModelsLoaded,scope:this}):this.fireEvent("appsettingsneeded")},getSettingsFields:function(){return[{name:"chartType",xtype:"rallycombobox",plugins:["rallyfieldvalidationui"],fieldLabel:"Chart Type",displayField:"name",valueField:"value",editable:!1,allowBlank:!1,store:Ext.create("Ext.data.Store",{fields:["name","value"],data:[{name:"Pie",value:"piechart"},{name:"Bar",value:"barchart"}]})},{name:"types",xtype:"rallycombobox",plugins:["rallyfieldvalidationui"],allowBlank:!1,editable:!1,autoSelect:!1,validateOnChange:!1,validateOnBlur:!1,fieldLabel:"Type",shouldRespondToScopeChange:!0,context:this.getContext(),storeConfig:{model:"TypeDefinition",sorters:[{property:"DisplayName"}],fetch:["DisplayName","TypePath"],filters:[{property:"UserListable",value:!0}],autoLoad:!1,remoteSort:!1,sortOnLoad:!0,remoteFilter:!0},displayField:"DisplayName",valueField:"TypePath",listeners:{change:function(combo){combo.fireEvent("typeselected",combo.getValue(),combo.context)},ready:function(combo){combo.fireEvent("typeselected",combo.getValue(),combo.context)}},bubbleEvents:["typeselected"],readyEvent:"ready",handlesEvents:{projectscopechanged:function(context){this.refreshWithNewContext(context)}}},{name:"aggregationField",xtype:"rallyfieldcombobox",plugins:["rallyfieldvalidationui"],fieldLabel:"Aggregate By",readyEvent:"ready",allowBlank:!1,validateOnChange:!1,validateOnBlur:!1,handlesEvents:{typeselected:function(models,context){var type=Ext.Array.from(models)[0];type?this.refreshWithNewModelType(type,context):(this.store.removeAll(),this.reset())}},listeners:{ready:function(combo){combo.store.filterBy(function(record){var field=record.get("fieldDefinition"),attr=field.attributeDefinition;return attr&&!attr.Hidden&&"COLLECTION"!==attr.AttributeType&&!field.isMappedFromArtifact});var fields=Ext.Array.map(combo.store.getRange(),function(record){return record.get(combo.getValueField())});Ext.Array.contains(fields,combo.getValue())||combo.setValue(fields[0])}}},{name:"aggregationType",xtype:"rallycombobox",plugins:["rallyfieldvalidationui"],fieldLabel:"Aggregation Type",displayField:"name",valueField:"value",editable:!1,allowBlank:!1,store:Ext.create("Ext.data.Store",{fields:["name","value"],data:[{name:"Count",value:"count"},{name:"Plan Estimate",value:"estimate"}]})},{type:"query"}]},_onModelsLoaded:function(models){this.models=_.values(models);var context=this.getContext(),modelNames=_.pluck(this.models,"typePath"),gridBoardConfig={xtype:"rallygridboard",toggleState:"chart",chartConfig:this._getChartConfig(),plugins:[{ptype:"rallygridboardinlinefiltercontrol",showInChartMode:!0,inlineFilterButtonConfig:{stateful:!0,stateId:context.getScopedStateId("filters"),filterChildren:!0,modelNames:modelNames,inlineFilterPanelConfig:{quickFilterPanelConfig:{defaultFields:this._getQuickFilters()}}}},{ptype:"rallygridboardactionsmenu",menuItems:[{text:"Export to CSV...",handler:function(){window.location=Rally.ui.gridboard.Export.buildCsvExportUrl(this.down("rallygridboard").getGridOrBoard())},scope:this}],buttonConfig:{iconCls:"icon-export",toolTipConfig:{html:"Export",anchor:"top",hideDelay:0}}}],context:context,modelNames:modelNames,storeConfig:{filters:this._getFilters()}};this.add(gridBoardConfig)},_getQuickFilters:function(){var quickFilters=[],types=this._getTypesSetting(),type=types[0];return types.length>1&&quickFilters.push("ModelType"),Rally.data.ModelTypes.isArtifact(type)&&(quickFilters.push("Owner"),Rally.data.ModelTypes.isPortfolioItem(type)?quickFilters.push("State"):quickFilters.push("ScheduleState")),quickFilters},_getTypesSetting:function(){return this.getSetting("types").split(",")},_getChartConfig:function(){return{xtype:this.getSetting("chartType"),storeType:"Rally.data.wsapi.artifact.Store",chartColors:["#FF8200","#F6A900","#FAD200","#8DC63F","#1E7C00","#337EC6","#005EB8","#7832A5","#DA1884","#C0C0C0"],storeConfig:{models:this._getTypesSetting(),context:this.getContext().getDataContext(),limit:1/0,fetch:this._getChartFetch(),sorters:this._getChartSort()},calculatorConfig:{calculationType:this.getSetting("aggregationType"),field:this.getSetting("aggregationField")}}},onTimeboxScopeChange:function(timeboxScope){this.callParent(arguments),this._addBoard()},_getChartFetch:function(){var field=this.getSetting("aggregationField"),fetch=["FormattedID","Name","PlanEstimate",field];return fetch},_getChartSort:function(){return[{property:this.getSetting("aggregationField"),direction:"ASC"}]},_getFilters:function(){var queries=[],timeboxScope=this.getContext().getTimeboxScope();return this.getSetting("query")&&queries.push(Rally.data.QueryFilter.fromQueryString(this.getSetting("query"))),timeboxScope&&_.any(this.models,timeboxScope.isApplicable,timeboxScope)&&queries.push(timeboxScope.getQueryFilter()),queries}});
Ext.define("CustomChartApp",{extend:"Rally.app.App",componentCls:"app",layout:"fit",config:{defaultSettings:{types:"defect",chartType:"piechart",aggregationField:"State",aggregationType:"count",query:""}},launch:function(){this.getSetting("types")?Rally.data.wsapi.ModelFactory.getModels({types:this._getTypesSetting()}).then({success:this._onModelsLoaded,scope:this}):this.fireEvent("appsettingsneeded")},getSettingsFields:function(){var me=this;return[{name:"chartType",xtype:"rallycombobox",plugins:["rallyfieldvalidationui"],fieldLabel:"Chart Type",displayField:"name",valueField:"value",editable:!1,allowBlank:!1,store:Ext.create("Ext.data.Store",{fields:["name","value"],data:[{name:"Pie",value:"piechart"},{name:"Bar",value:"barchart"}]})},{name:"types",xtype:"rallycombobox",plugins:["rallyfieldvalidationui"],allowBlank:!1,editable:!1,autoSelect:!1,validateOnChange:!1,validateOnBlur:!1,fieldLabel:"Type",shouldRespondToScopeChange:!0,context:this.getContext(),storeConfig:{model:"TypeDefinition",sorters:[{property:"DisplayName"}],fetch:["DisplayName","TypePath"],filters:[{property:"UserListable",value:!0}],autoLoad:!1,remoteSort:!1,sortOnLoad:!0,remoteFilter:!0},displayField:"DisplayName",valueField:"TypePath",listeners:{change:function(combo){combo.fireEvent("typeselected",combo.getValue(),combo.context)},ready:function(combo){combo.fireEvent("typeselected",combo.getValue(),combo.context)}},bubbleEvents:["typeselected"],readyEvent:"ready",handlesEvents:{projectscopechanged:function(context){this.refreshWithNewContext(context)}}},{name:"aggregationField",xtype:"rallyfieldcombobox",plugins:["rallyfieldvalidationui"],fieldLabel:"Aggregate By",readyEvent:"ready",allowBlank:!1,validateOnChange:!1,validateOnBlur:!1,handlesEvents:{typeselected:function(models,context){var type=Ext.Array.from(models)[0];type?this.refreshWithNewModelType(type,context):(this.store.removeAll(),this.reset())}},listeners:{ready:function(combo){combo.store.filterBy(function(record){var field=record.get("fieldDefinition"),attr=field.attributeDefinition;return attr&&!attr.Hidden&&"COLLECTION"!==attr.AttributeType&&!field.isMappedFromArtifact});var fields=Ext.Array.map(combo.store.getRange(),function(record){return record.get(combo.getValueField())});Ext.Array.contains(fields,combo.getValue())||combo.setValue(fields[0])}}},{name:"aggregationType",xtype:"rallycombobox",plugins:["rallyfieldvalidationui"],fieldLabel:"Aggregation Type",displayField:"name",valueField:"value",editable:!1,allowBlank:!1,store:Ext.create("Ext.data.Store",{fields:["name","value"],data:[{name:"Count",value:"count"},{name:"Plan Estimate",value:"estimate"},{name:"Leaf Story Plan Estimate Total",value:"leafplanest"},{name:"Preliminary Estimate Value",value:"prelimest"}]}),handlesEvents:{typeselected:function(types,context){var type=Ext.Array.from(types)[0];Rally.data.ModelFactory.getModel({type:type,success:function(model){this.store.filterBy(function(record){return"count"===record.get("value")||model.hasField(me._getFieldForAggregationType(record.get("value")))})},scope:this})}}},{type:"query"}]},_onModelsLoaded:function(models){this.models=_.values(models);var context=this.getContext(),modelNames=_.pluck(this.models,"typePath"),gridBoardConfig={xtype:"rallygridboard",toggleState:"chart",chartConfig:this._getChartConfig(),plugins:[{ptype:"rallygridboardinlinefiltercontrol",showInChartMode:!0,inlineFilterButtonConfig:{stateful:!0,stateId:context.getScopedStateId("filters"),filterChildren:!0,modelNames:modelNames,inlineFilterPanelConfig:{quickFilterPanelConfig:{defaultFields:this._getQuickFilters()}}}},{ptype:"rallygridboardactionsmenu",menuItems:[{text:"Export to CSV...",handler:function(){window.location=Rally.ui.gridboard.Export.buildCsvExportUrl(this.down("rallygridboard").getGridOrBoard())},scope:this}],buttonConfig:{iconCls:"icon-export",toolTipConfig:{html:"Export",anchor:"top",hideDelay:0}}}],context:context,modelNames:modelNames,storeConfig:{filters:this._getFilters()}};this.add(gridBoardConfig)},_getQuickFilters:function(){var quickFilters=[],types=this._getTypesSetting(),type=types[0];return types.length>1&&quickFilters.push("ModelType"),Rally.data.ModelTypes.isArtifact(type)&&(quickFilters.push("Owner"),Rally.data.ModelTypes.isPortfolioItem(type)?quickFilters.push("State"):quickFilters.push("ScheduleState")),quickFilters},_getTypesSetting:function(){return this.getSetting("types").split(",")},_getChartConfig:function(){return{xtype:this.getSetting("chartType"),storeType:"Rally.data.wsapi.artifact.Store",chartColors:["#FF8200","#F6A900","#FAD200","#8DC63F","#1E7C00","#337EC6","#005EB8","#7832A5","#DA1884","#C0C0C0"],storeConfig:{models:this._getTypesSetting(),context:this.getContext().getDataContext(),limit:1/0,fetch:this._getChartFetch(),sorters:this._getChartSort()},calculatorConfig:{calculationType:this.getSetting("aggregationType"),field:this.getSetting("aggregationField")}}},onTimeboxScopeChange:function(timeboxScope){this.callParent(arguments),this._addBoard()},_getChartFetch:function(){var field=this.getSetting("aggregationField"),aggregationType=this.getSetting("aggregationType"),fetch=["FormattedID","Name",field];return"count"!==aggregationType&&fetch.push(this._getFieldForAggregationType(aggregationType)),fetch},_getFieldForAggregationType:function(aggregationType){return"estimate"===aggregationType?"PlanEstimate":"prelimest"===aggregationType?"PreliminaryEstimateValue":"leafplanest"===aggregationType?"LeafStoryPlanEstimateTotal":void 0},_getChartSort:function(){return[{property:this.getSetting("aggregationField"),direction:"ASC"}]},_getFilters:function(){var queries=[],timeboxScope=this.getContext().getTimeboxScope();return this.getSetting("query")&&queries.push(Rally.data.QueryFilter.fromQueryString(this.getSetting("query"))),timeboxScope&&_.any(this.models,timeboxScope.isApplicable,timeboxScope)&&queries.push(timeboxScope.getQueryFilter()),queries}});

Rally.launchApp('CustomChartApp', {
name:"Custom Chart",
Expand Down
Loading

0 comments on commit 69bdd40

Please sign in to comment.