Commit 55bf8be3 authored by LE GAC Renaud's avatar LE GAC Renaud
Browse files

Redesign the metric view using grid and its plugin Export.

parent c3353135
""" Controllers for building metrics tables
"""
import json
import re
from gluon.dal import smart_query
......@@ -32,6 +33,7 @@ def index():
metric = db.metrics[selector.id_metrics]
# database fields corresponding to the axes
# correspondence is (column, row) = (y, x)
fields, orderby = [], []
for el in ('column', 'row'):
......@@ -63,24 +65,29 @@ def index():
q_end = db.publications.year <= selector.year_end
query = (query) & ((q_start) & (q_end))
# build the table object
header_columns, field = [], fields[0]
# get the label along the x and y axis
# x axis is horizontal while the y axis is vertical
# correspondence is (column, row) = (y, x)
header_y, field = [], fields[0]
for row in db(query).select(fields[0], distinct=True, orderby=orderby[0]):
header_columns.append(row[field])
header_y.append(row[field])
header_rows, field = [], fields[1]
header_x, field = [], fields[1]
for row in db(query).select(fields[1], distinct=True, orderby=orderby[1]):
header_rows.append(row[field])
header_x.append(row[field])
# the fields configuration of the Ext.data.ArrayStore
# it include a sum per row
cfg = dict(fields=[], data=[])
table = [['']]
table[-1].extend(header_rows)
cfg['fields'].append({'name': fields[0].name, 'type': 'string'})
for el in header_x:
cfg['fields'].append({'name': str(el), 'type': 'int'})
cfg['fields'].append({'name': T('Total'), 'type': 'int'})
for el in header_columns:
table.append([el])
table[-1].extend(['']*len(header_rows))
# fill the table with value from the database
# fill the data block of the Ext.data.Array.Store
# transform (x, y count) data point into a row of values
count = db.publications.id.count()
rows = db(query).select(fields[0],
fields[1],
......@@ -88,22 +95,31 @@ def index():
groupby=fields,
orderby=orderby)
key = None
for row in rows:
icol = header_columns.index(row[fields[0]]) + 1
irow = header_rows.index(row[fields[1]]) + 1
table[icol][irow] = row[count]
if row[fields[0]] != key:
key = row[fields[0]]
cfg['data'].append([key])
cfg['data'][-1].extend(['']*(len(header_x) + 1))
cfg['data'][-1][-1] = 0
i = header_x.index(row[fields[1]]) + 1
cfg['data'][-1][i] = row[count]
cfg['data'][-1][-1] += row[count]
# Substitute axis label
cvt_labels = get_converter(metric)
for i in range(len(table[0])):
if table[0][i] in cvt_labels:
table[0][i] = cvt_labels[table[0][i]]
for i in range(len(cfg['data'][0])):
if cfg['data'][0][i] in cvt_labels:
cfg['data'][0][i] = cvt_labels[cfg['data'][0][i]]
for i in range(len(table)):
if table[i][0] in cvt_labels:
table[i][0] = cvt_labels[table[i][0]]
for i in range(len(cfg['data'])):
if cfg['data'][i][0] in cvt_labels:
cfg['data'][i][0] = cvt_labels[cfg['data'][i][0]]
return dict(table=table,
return dict(cfg_store=json.dumps(cfg),
team_project=repr_team_project(db, selector),
selector=selector)
......@@ -597,6 +597,7 @@
'too short': 'too short',
'Tools': 'Outils',
'total': 'total',
'Total': 'Total',
'Town': 'Ville',
'Tr Axis': 'Tr Axis',
'Tr Granularity': 'Tr Granularity',
......
......@@ -12,13 +12,11 @@ virtdb.define_table('metric_selector',
Field('year_end', 'integer'),
Field('id_teams', 'reference teams', label='Team'),
Field('id_projects', 'reference projects', label='Project'),
Field('id_metrics', 'reference metrics', label='Metric'),
Field('format', 'string', default='html'))
Field('id_metrics', 'reference metrics', label='Metric'))
virtdb.metric_selector.id_projects.requires = IS_IN_DB(db, 'projects.project')
virtdb.metric_selector.id_teams.requires = IS_IN_DB(db, 'teams.team')
virtdb.metric_selector.id_metrics.requires = IS_IN_DB(db, 'metrics.metric')
virtdb.metric_selector.format.requires = IS_IN_SET(['html', 'csv'])
#-------------------------------------------------------------------------------
#
......
......@@ -15,7 +15,7 @@ HEAD
It can be run standalone or launched from the harvester report.
- Refactor the ux files to ease the buiding of a new database from scratch.
- Use the new callbacks INHIBIT_DELETE_UNDEF and INHIBIT_UPDATE_UNDEF.
- Redesing the lists and metrics interfaces.
- Redesing the lists and metrics interfaces as well as metric view.
- Remove obsolete controller toolbox. It is now replaced by standalone
scripts: export-to-csv, import-from-csv, fix-conference-dates, fix-country,
fix-defense, fix-submitted
......
{{
import cStringIO
import csv
fn = 'metrics.csv'
response.headers['Content-Type'] = 'application/csv'
response.headers['Content-Disposition'] = 'attachment; filename=%s;' % fn
fi = cStringIO.StringIO()
writer = csv.writer(fi, quoting=csv.QUOTE_MINIMAL)
writer.writerows(table)
response.write(fi.getvalue(), escape=False)
fi.close()
}}
\ No newline at end of file
{{
#--------------------------------------------------------------------------
#
# HEADER
# The python controller return:
# - cfg_store, the configuration of the Ext.data.Array
# - team_project string
# - selector object
#
title = "%s %s" % (T("Publications"), team_project)
response.write(P(title, _class="my-p my-small-cap my-large"))
# prepare the data
# - build unique DIV identifier
# - Title and DIV block
#
#--------------------------------------------------------------------------
#
# HTML table
# unique identifier for the DIV block associated to the grid
#
headers = [TD(el, _class="my-td") for el in table[0]]
html_table = TABLE(TR(*headers, _class="my-tr"), _class="my-table")
divgrid = "grid-%s" % id(cfg_store)
#
# The title and the DIV block for the Ext.grid.Panel
#
title = "%s %s" % (T("Publications"), team_project)
response.write(H2(title, _class="dbui-h2 dbui-small-cap"))
response.write(DIV(_id=divgrid))
for i in range(1, len(table)):
cells = [TD(el, _class="my-td my-right") for el in table[i]]
cells[0]["_class"] = "my-td my-left"
html_table.append(TR(*cells, _class="my-tr"))
pass
response.write(CENTER(html_table))
response.write(BR())
#
# FOOTER
# The footer
#
# Add the URL providing a direct access to this list.
# The application use the POST method will a user will use the GET one.
# Display the URL only in the first case.
#
#
if request.env.request_method == 'POST':
html_url = A("url", _href=selector.repr_url())
=P(T("Direct access to the table: "), html_url, _class="my-p")
=P(request.now.strftime("%d %b %Y %H:%M"), _class="my-p")
html_url = A("url", _href=selector.repr_url(), _target='_blank')
=P(T("Direct access to the table: "), html_url, _class="dbui-p")
=P(request.now.strftime("%d %b %Y %H:%M"), _class="dbui-p")
=BR()
pass
#
# Export python variables to the javascript
#
jsvars = ["cfgStore = %s" % cfg_store,
"columns = []",
"divgrid = '%s'" % divgrid,
"i"]
jsvars = " var %s;" % ',\n'.join(jsvars)
response.write(SCRIPT(jsvars), escape=False)
}}
<script>
/**
* Renderer functions
*
* @param {Object} value
* @param {Object} metadata
* @param {Ext.data.Model} record
* @param {Number} rowIndex
* @param {Number} colIndex
* @param {Ext.data.Store} store
* @param {Ext.view.view} view
*
*/
function rTotal() {
return 'Total';
}
//
// check that the Ext JS library is loaded
//
if (typeof Ext === "undefined") {
alert("The javascript library Ext JS is missing !");
}
//
// The first column contains labels for the vertical axis
//
columns.push({
text: cfgStore.fields[0].name,
dataIndex: cfgStore.fields[0].name,
summaryRenderer: rTotal,
flex: 1.5
});
//
// the others columns contains publication count
//
for (i = 1; i < cfgStore.fields.length; i += 1) {
columns.push({
text: cfgStore.fields[i].name,
dataIndex: cfgStore.fields[i].name,
align: 'right',
summaryType: 'sum',
flex: 0.8
});
}
//
// instantiate the grid with a summary row.
// data can be extracted via the plugin pGridExport
//
var grid = Ext.create('Ext.grid.Panel', {
plugins: ['pGridExport'],
store: Ext.create('Ext.data.ArrayStore', cfgStore),
columns: columns,
features: [{ftype:'summary'}],
forceFit: true,
hideHeaders: false,
padding: "10 40 20 60",
renderTo: divgrid
});
</script>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment