Skip to content
Snippets Groups Projects
Commit 22af57b6 authored by Allen Gilliland's avatar Allen Gilliland
Browse files

update pivot implementation to handle all the pivoting logic inside the...

update pivot implementation to handle all the pivoting logic inside the VisualizationTable component and lessen the work inside the Visualization wrapper.
parent c7e010c1
Branches
Tags
No related merge requests found
'use strict';
/*global _*/
var ExploreServices = angular.module('corvus.explore.services', []);
ExploreServices.service('CorvusFormGenerator', [function() {
// Valid Operators per field
import SchemaMetadata from "metabase/lib/schema_metadata";
var DateBaseTypes = ['DateTimeField', 'DateField'];
var DateSpecialTypes = ['timestamp_milliseconds', 'timestamp_seconds'];
var NumberBaseTypes = ['IntegerField', 'DecimalField', 'FloatField', 'BigIntegerField'];
var SummableBaseTypes = ['IntegerField', 'DecimalField', 'FloatField', 'BigIntegerField'];
var CategoryBaseTypes = ["BooleanField"];
var CategorySpecialTypes = ["category", "zip_code", "city", "state", "country"];
function isInTypes(type, type_collection) {
if (_.indexOf(type_collection, type) >= 0) {
return true;
}
return false;
var ExploreServices = angular.module('corvus.explore.services', []);
}
ExploreServices.service('CorvusFormGenerator', [function() {
// Valid Operators per field
function isDate(field) {
return isInTypes(field.base_type, DateBaseTypes) || isInTypes(field.special_type, DateSpecialTypes);
return SchemaMetadata.isDateType(field);
}
function isNumber(field) {
return isInTypes(field.base_type, NumberBaseTypes);
return SchemaMetadata.isNumericType(field);
}
function isSummable(field) {
return isInTypes(field.base_type, SummableBaseTypes);
return SchemaMetadata.isSummableType(field);
}
function isCategory(field) {
return isInTypes(field.base_type, CategoryBaseTypes) || isInTypes(field.special_type, CategorySpecialTypes);
return SchemaMetadata.isCategoryType(field);
}
function isDimension(field) {
return isDate(field) || isCategory(field) || isInTypes(field.field_type, ['dimension']);
return SchemaMetadata.isDimension(field);
}
......
'use strict';
/*global _*/
import SchemaMetadata from "metabase/lib/schema_metadata";
function compareNumbers(a, b) {
return a - b;
}
var DataGrid = {
pivot: function(data) {
......@@ -20,8 +26,18 @@ var DataGrid = {
}
// sort the column values sensibly
pivotColValues.sort();
normalColValues.sort();
if (SchemaMetadata.isNumericType(data.cols[pivotCol])) {
pivotColValues.sort(compareNumbers);
} else {
pivotColValues.sort();
}
if (SchemaMetadata.isNumericType(data.cols[normalCol])) {
normalColValues.sort(compareNumbers);
} else {
normalColValues.sort();
}
// make sure that the first element in the pivoted column list is null which makes room for the label of the other column
pivotColValues.unshift(null);
......
'use strict';
/*global _*/
var DateBaseTypes = ['DateTimeField', 'DateField'];
var DateSpecialTypes = ['timestamp_milliseconds', 'timestamp_seconds'];
var NumberBaseTypes = ['IntegerField', 'DecimalField', 'FloatField', 'BigIntegerField'];
var SummableBaseTypes = ['IntegerField', 'DecimalField', 'FloatField', 'BigIntegerField'];
var CategoryBaseTypes = ["BooleanField"];
var CategorySpecialTypes = ["category", "zip_code", "city", "state", "country"];
function isInTypes(type, type_collection) {
if (_.indexOf(type_collection, type) >= 0) {
return true;
}
return false;
}
var SchemaMetadata = {
isDateType: function(field) {
return isInTypes(field.base_type, DateBaseTypes) || isInTypes(field.special_type, DateSpecialTypes);
},
isNumericType: function(field) {
return isInTypes(field.base_type, NumberBaseTypes);
},
isSummableType: function(field) {
return isInTypes(field.base_type, SummableBaseTypes);
},
isCategoryType: function(field) {
return isInTypes(field.base_type, CategoryBaseTypes) || isInTypes(field.special_type, CategorySpecialTypes);
},
isDimension: function(field) {
return SchemaMetadata.isDateType(field) || SchemaMetadata.isCategoryType(field) || isInTypes(field.field_type, ['dimension']);
}
};
export default SchemaMetadata;
......@@ -196,7 +196,7 @@ export default React.createClass({
} else if (this.props.card.display === "table") {
var tableData = this.props.result.data,
var pivotTable = false,
cellClickable = this.props.cellIsClickableFn,
sortFunction = this.props.setSortFn,
sort = (this.props.card.dataset_query.query && this.props.card.dataset_query.query.order_by) ?
......@@ -205,15 +205,16 @@ export default React.createClass({
// check if the data is pivotable (2 groupings + 1 agg != 'rows')
if (Query.isStructured(this.props.card.dataset_query) &&
!Query.isBareRowsAggregation(this.props.card.dataset_query.query) &&
tableData.cols.length === 3) {
tableData = DataGrid.pivot(this.props.result.data);
this.props.result.data.cols.length === 3) {
pivotTable = true;
sortFunction = undefined;
cellClickable = function() { return false; };
}
viz = (
<QueryVisualizationTable
data={tableData}
data={this.props.result.data}
pivot={pivotTable}
maxRows={this.props.maxTableRows}
setSortFn={sortFunction}
sort={sort}
......
......@@ -2,6 +2,7 @@
/*global _*/
import MetabaseAnalytics from '../lib/analytics';
import DataGrid from "metabase/lib/data_grid";
import FixedDataTable from 'fixed-data-table';
import Icon from './icon.react';
......@@ -45,7 +46,8 @@ export default React.createClass({
componentWillMount: function() {
if (this.props.data) {
this.setState({
colDefs: JSON.stringify(this.props.data.cols)
colDefs: JSON.stringify(this.props.data.cols),
data: (this.props.pivot) ? DataGrid.pivot(this.props.data) : this.props.data
});
}
},
......@@ -54,9 +56,11 @@ export default React.createClass({
// TODO: check if our data has changed and specifically if our columns list has changed
if (JSON.stringify(newProps.data.cols) !== this.state.colDefs) {
// if the columns have changed then reset any column widths we have setup
var gridData = (newProps.pivot) ? DataGrid.pivot(newProps.data) : newProps.data;
this.setState({
colDefs: JSON.stringify(this.props.data.cols),
columnWidths: this.calculateColumnWidths(this.state.width, this.props.minColumnWidth, newProps.data.cols)
columnWidths: this.calculateColumnWidths(this.state.width, this.props.minColumnWidth, gridData.cols),
data: gridData
});
}
},
......@@ -68,7 +72,7 @@ export default React.createClass({
shouldComponentUpdate: function(nextProps, nextState) {
// this is required because we don't pass in the containing element size as a property :-/
// if size changes don't update yet because state will change in a moment
this.calculateSizing(nextState)
this.calculateSizing(nextState);
// compare props and state to determine if we should re-render
// NOTE: this is essentially the same as React.addons.PureRenderMixin but
......@@ -109,7 +113,7 @@ export default React.createClass({
if (width !== prevState.width) {
// NOTE: we remove 2 pixels from width to allow for a border pixel on each side
var tableColumnWidths = this.calculateColumnWidths(width - 2, this.props.minColumnWidth, this.props.data.cols, prevState.width, prevState.columnWidths);
var tableColumnWidths = this.calculateColumnWidths(width - 2, this.props.minColumnWidth, this.state.data.cols, prevState.width, prevState.columnWidths);
updatedState.columnWidths = tableColumnWidths;
}
......@@ -140,8 +144,8 @@ export default React.createClass({
var row = {
hasPopover: this.state.popover && this.state.popover.rowIndex === rowIndex || false
};
for (var i = 0; i < this.props.data.rows[rowIndex].length; i++) {
row[i] = this.props.data.rows[rowIndex][i];
for (var i = 0; i < this.state.data.rows[rowIndex].length; i++) {
row[i] = this.state.data.rows[rowIndex][i];
}
return row;
},
......@@ -206,10 +210,14 @@ export default React.createClass({
},
tableHeaderRenderer: function(columnIndex) {
var column = this.props.data.cols[columnIndex],
var column = this.state.data.cols[columnIndex],
colVal = (column && column.display_name && column.display_name.toString()) ||
(column && column.name && column.name.toString());
if (!colVal && this.props.pivot && columnIndex !== 0) {
colVal = "Unset";
}
var headerClasses = cx({
'MB-DataTable-header' : true,
'flex': true,
......@@ -242,12 +250,12 @@ export default React.createClass({
},
render: function() {
if(!this.props.data) {
if(!this.state.data) {
return false;
}
var component = this;
var tableColumns = this.props.data.cols.map(function (column, idx) {
var tableColumns = this.state.data.cols.map(function (column, idx) {
var colVal = (column !== null) ? column.name.toString() : null;
var colWidth = component.state.columnWidths[idx];
......@@ -274,7 +282,7 @@ export default React.createClass({
className="MB-DataTable"
rowHeight={35}
rowGetter={this.rowGetter}
rowsCount={this.props.data.rows.length}
rowsCount={this.state.data.rows.length}
width={this.state.width}
maxHeight={this.state.height}
headerHeight={50}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment