Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SIP-5] Refactor pivot table #5705

Merged
merged 3 commits into from
Sep 5, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 75 additions & 23 deletions superset/assets/src/visualizations/pivot_table.js
Original file line number Diff line number Diff line change
@@ -1,51 +1,78 @@
import dt from 'datatables.net-bs';
import 'datatables.net-bs/css/dataTables.bootstrap.css';
import $ from 'jquery';

import PropTypes from 'prop-types';
import { d3format, fixDataTableBodyHeight } from '../modules/utils';
import './pivot_table.css';

dt(window, $);

module.exports = function (slice, payload) {
const container = slice.container;
const fd = slice.formData;
const height = container.height();
let cols = payload.data.columns;
if (Array.isArray(cols[0])) {
cols = cols.map(col => col[0]);
}
const propTypes = {
data: PropTypes.shape({
// TODO: replace this with raw data in SIP-6
html: PropTypes.string,
columns: PropTypes.arrayOf(PropTypes.oneOfType([
PropTypes.string,
PropTypes.arrayOf(PropTypes.string),
])),
}),
height: PropTypes.number,
columnFormats: PropTypes.objectOf(PropTypes.string),
groupBy: PropTypes.arrayOf(PropTypes.string),
numberFormat: PropTypes.string,
verboseMap: PropTypes.objectOf(PropTypes.string),
};

function PivotTable(element, props) {
PropTypes.checkPropTypes(propTypes, props, 'prop', 'PivotTable');

const {
data,
height,
columnFormats,
groupBy,
numberFormat,
verboseMap,
} = props;

const { html, columns } = data;
const container = element;
const $container = $(element);

// payload data is a string of html with a single table element
container.html(payload.data.html);
container.innerHTML = html;

const cols = Array.isArray(columns[0])
? columns.map(col => col[0])
: columns;

// jQuery hack to set verbose names in headers
const replaceCell = function () {
const s = $(this)[0].textContent;
$(this)[0].textContent = slice.datasource.verbose_map[s] || s;
$(this)[0].textContent = verboseMap[s] || s;
};
slice.container.find('thead tr:first th').each(replaceCell);
slice.container.find('thead tr th:first-child').each(replaceCell);
$container.find('thead tr:first th').each(replaceCell);
$container.find('thead tr th:first-child').each(replaceCell);

// jQuery hack to format number
slice.container.find('tbody tr').each(function () {
$container.find('tbody tr').each(function () {
$(this).find('td').each(function (i) {
const metric = cols[i];
const format = slice.datasource.column_formats[metric] || fd.number_format || '.3s';
const format = columnFormats[metric] || numberFormat || '.3s';
const tdText = $(this)[0].textContent;
if (!isNaN(tdText) && tdText !== '') {
if (!Number.isNaN(tdText) && tdText !== '') {
$(this)[0].textContent = d3format(format, tdText);
}
});
});

if (fd.groupby.length === 1) {
if (groupBy.length === 1) {
// When there is only 1 group by column,
// we use the DataTable plugin to make the header fixed.
// The plugin takes care of the scrolling so we don't need
// overflow: 'auto' on the table.
container.css('overflow', 'hidden');
const table = container.find('table').DataTable({
container.style.overflow = 'hidden';
const table = $container.find('table').DataTable({
paging: false,
searching: false,
bInfo: false,
Expand All @@ -54,12 +81,37 @@ module.exports = function (slice, payload) {
scrollX: true,
});
table.column('-1').order('desc').draw();
fixDataTableBodyHeight(container.find('.dataTables_wrapper'), height);
fixDataTableBodyHeight($container.find('.dataTables_wrapper'), height);
} else {
// When there is more than 1 group by column we just render the table, without using
// the DataTable plugin, so we need to handle the scrolling ourselves.
// In this case the header is not fixed.
container.css('overflow', 'auto');
container.css('height', `${height + 10}px`);
container.style.overflow = 'auto';
container.style.height = `${height + 10}px`;
}
};
}

function adaptor(slice, payload) {
const { selector, formData, datasource } = slice;
const {
groupby: groupBy,
number_format: numberFormat,
} = formData;
const {
column_formats: columnFormats,
verbose_map: verboseMap,
} = datasource;
const element = document.querySelector(selector);

return PivotTable(element, {
data: payload.data,
height: slice.height(),
columnFormats,
groupBy,
numberFormat,
verboseMap,
});
}

export default adaptor;