Rally: Using custom data with TreeStoreBuilder and rallygridboard

448 Views Asked by At

I'm trying to create a Rally page that displays custom data and allows me to export the data to Excel. I'm struggling because I can either display the data in a rallygrid (which allows me to calculate custom fields and display them), or I can display the data in a rallygridboard (which allows me to export data), but I don't seem to be able to do both.

Anyone have any ideas about what I could do to make this work?

The custom data I want to display is the user story's Feature's parent Initiative name, fwiw.

There's code in Rally's examples that shows how to display custom data in a grid. I won't paste the full code here to save space, but here's a relevant snippet from their example:

        launch: function() {
                Ext.create('Rally.data.wsapi.Store', {
                    model: 'userstory',
                    autoLoad: true,
                    listeners: {
                        load: this._onDataLoaded,
                        scope: this
                    },
                    fetch: ['FormattedID', 'Name', 'ScheduleState', 'Tasks', 'Defects']
                });
            },

            _onDataLoaded: function(store, data) {
                var records = _.map(data, function(record) {
                    //Perform custom actions with the data here
                    //Calculations, etc.
                    return Ext.apply({
                        TaskCount: record.get('Tasks').Count
                    }, record.getData());
                });

           this.add({
                    xtype: 'rallygrid',
                    showPagingToolbar: false,
                    showRowActionsColumn: false,
                    editable: false,
                    store: Ext.create('Rally.data.custom.Store', {
                        data: records
                    }),

....

This works great with a rallygrid, but rallygrid doesn't seem to support exporting to csv.

That same approach (using _onDataLoaded) doesn't work when I switch the rallygrid to be a rallygridboard. I get an error in _onDataLoaded on this line: var feature = record.get('Feature'); The error I get is: "record.get is not a function"

Here's my full code. Note that this is coded to get the data I actually want (which is user story stuff), rather than Tasks (which was just the Rally example file).

<!DOCTYPE html>
<html>
<head>
<title>Exportable Grid Board Example</title>

<script type="text/javascript" src="/apps/2.1/sdk.js"></script>

<script type="text/javascript">
    var recordCount = 0;

    Rally.onReady(function() {
        Ext.define('Rally.example.ExportableGridBoard', {
            extend: 'Rally.app.App',
            componentCls: 'app',

            launch: function() {
                Ext.create('Rally.data.wsapi.TreeStoreBuilder').build({
                    models: ['portfolioitem/feature','userstory'],
                    autoLoad: true,
                    enableHierarchy: true,
                    listeners: {
                        load: this._onDataLoaded,
                        scope: this
                    }
                }).then({
                    success: this._onStoreBuilt,
                    scope: this
                });
            },

            _onDataLoaded: function (store, data) {
                var records = _.map(data, function (record) {
                    //Perform custom actions with the data here
                    //Calculations, etc.

                    //console.log(record);
                    recordCount++;

                    var feature = record.get('Feature');

                    var featureName;
                    var initiative;
                    var initiativeName;

                    if (feature == null) {
                        featureName = '';
                        initiative = '';
                        initiativeName = '';
                    }
                    else {
                        featureName = feature.FormattedID + ' ' + feature.Name;
                        initiative = feature.Parent;

                        if (initiative == null) {
                            initiativeName = '';
                        }
                        else {
                            initiativeName = initiative.FormattedID + ' ' + initiative.Name;
                        }

                    }

                    return Ext.apply({
                            featureName: featureName,
                            initiativeName: initiativeName
                        }, record.getData());
                })
            },//_onDataLoaded


            _onStoreBuilt: function(store) {

                //this._onDataLoaded(store, store.data);

                //console.log('num records: '+ recordCount);//seems to always be 0

                var modelNames = ['userstory'],
                    context = this.getContext();

                this.add({
                    xtype: 'rallygridboard',
                    context: context,
                    modelNames: modelNames,
                    toggleState: 'grid',
                    stateful: false,
                    plugins: [
                        {
                            ptype: 'rallygridboardactionsmenu',
                            menuItems: [
                                {
                                    text: 'Export...',
                                    handler: function() {
                                        window.location = Rally.ui.gridboard.Export.buildCsvExportUrl(
                                            this.down('rallygridboard').getGridOrBoard());
                                    },
                                    scope: this
                                }
                            ],
                            buttonConfig: {
                                iconCls: 'icon-export'
                            }
                        }
                    ],
                    gridConfig: {
                        store: store,
                        columnCfgs: [
                            'Name',
                            'ScheduleState',
                            //'c_AffinityEstimate',
                            'PlanEstimate',
                            'Project',
                            'Feature',
                            'Feature.Parent',
                            'featureName',
                            'initiativeName'
                        ]
                    },
                    height: this.getHeight()
                });
            }
        });


        Rally.launchApp('Rally.example.ExportableGridBoard', {
          name: 'Exportable Grid Board Example'
        });
    });
</script>

<style type="text/css">

</style>
</head>
<body></body>
</html>
1

There are 1 best solutions below

1
On

Exporting data is only supported for grids where all the data was populated from a WSAPI query. In order to export your custom data you'll have to manually write some code to generate the CSV string on the client and then trigger a download using a data URI.

I tried to find an example of an app doing this but came up empty. Here's a description of the approach though:

https://developer.zendesk.com/blog/app-tricks-generate-csv-files-for-download-with-handlebars-and-data-uris

You'll just loop over each record in your story and then build the , separated string and you can link to the result or you can just set window.location to the result.