Compare commits
19 Commits
QB-331/Piv
...
QB-285-con
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
73011d0388 | ||
|
|
41cf77e8d2 | ||
|
|
1355381346 | ||
|
|
730f35a83c | ||
|
|
71bf25e8fb | ||
|
|
9b4fe54239 | ||
|
|
e59c594215 | ||
|
|
97a54e6f5a | ||
|
|
eac9fd2a5f | ||
|
|
96f09f9323 | ||
|
|
2ab340f3f1 | ||
|
|
58d0f542eb | ||
|
|
8ba826a0ea | ||
|
|
d2446395e2 | ||
|
|
f17a7b7714 | ||
|
|
8aa86275f0 | ||
|
|
3ebc2b9e29 | ||
|
|
ce81549011 | ||
|
|
e64af66dab |
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"json.format.enable": false
|
||||
}
|
||||
@@ -1,14 +1,16 @@
|
||||
/* eslint-disable react/sort-prop-types */
|
||||
/* eslint-disable space-before-function-paren */
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Tooltip from '../tooltip/index.jsx';
|
||||
|
||||
class DataCell extends React.PureComponent {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.handleSelect = this.handleSelect.bind(this);
|
||||
}
|
||||
|
||||
handleSelect () {
|
||||
handleSelect() {
|
||||
const {
|
||||
data: {
|
||||
meta: {
|
||||
@@ -26,14 +28,14 @@ class DataCell extends React.PureComponent {
|
||||
if (!allowFilteringByClick) {
|
||||
return;
|
||||
}
|
||||
|
||||
component.backendApi.selectValues(0, [measurement.parents.dimension1.elementNumber], false);
|
||||
// fixes the console error on selection made from data cells
|
||||
component.selectValues(0, [measurement.parents.dimension1.elementNumber], false);
|
||||
if (hasSecondDimension) {
|
||||
component.backendApi.selectValues(1, [measurement.parents.dimension2.elementNumber], false);
|
||||
component.selectValues(1, [measurement.parents.dimension2.elementNumber], false);
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
const {
|
||||
cellWidth,
|
||||
measurement,
|
||||
@@ -41,9 +43,9 @@ class DataCell extends React.PureComponent {
|
||||
styling
|
||||
} = this.props;
|
||||
|
||||
let textAlignment = styling.options.textAlignment || 'Right';
|
||||
const textAlignment = styling.options.textAlignment || 'Right';
|
||||
|
||||
let cellStyle = {
|
||||
const cellStyle = {
|
||||
fontFamily: styling.options.fontFamily,
|
||||
...styleBuilder.getStyle(),
|
||||
paddingLeft: '5px',
|
||||
@@ -64,10 +66,10 @@ class DataCell extends React.PureComponent {
|
||||
const { conditionalColoring } = styling;
|
||||
if (conditionalColoring.enabled) {
|
||||
const isValidConditionalColoringValue = !styleBuilder.hasComments() && !isNaN(measurement.value);
|
||||
const isSpecifiedRow =
|
||||
conditionalColoring.rows.indexOf(measurement.parents.dimension1.header) !== -1;
|
||||
const isSpecifiedMeasure =
|
||||
conditionalColoring.measures.indexOf(measurement.parents.measurement.index) !== -1;
|
||||
const isSpecifiedRow
|
||||
= conditionalColoring.rows.indexOf(measurement.parents.dimension1.header) !== -1;
|
||||
const isSpecifiedMeasure
|
||||
= conditionalColoring.measures.indexOf(measurement.parents.measurement.index) !== -1;
|
||||
const shouldHaveConditionalColoring = (conditionalColoring.colorAllRows || isSpecifiedRow)
|
||||
&& (conditionalColoring.colorAllMeasures || isSpecifiedMeasure);
|
||||
if (isValidConditionalColoringValue && shouldHaveConditionalColoring) {
|
||||
@@ -112,7 +114,7 @@ DataCell.propTypes = {
|
||||
}).isRequired,
|
||||
component: PropTypes.shape({
|
||||
backendApi: PropTypes.shape({
|
||||
selectValues: function (props, propName) {
|
||||
selectValues (props, propName) {
|
||||
if (props.isSnapshot || typeof props[propName] === 'function') {
|
||||
return null;
|
||||
}
|
||||
@@ -130,7 +132,7 @@ DataCell.propTypes = {
|
||||
|
||||
export default DataCell;
|
||||
|
||||
function formatMeasurementValue (measurement, styling) {
|
||||
function formatMeasurementValue(measurement, styling) {
|
||||
if (isNaN(measurement.value)) {
|
||||
return styling.symbolForNulls;
|
||||
}
|
||||
@@ -138,7 +140,7 @@ function formatMeasurementValue (measurement, styling) {
|
||||
return measurement.displayValue;
|
||||
}
|
||||
|
||||
function getConditionalColor (measurement, conditionalColoring) {
|
||||
function getConditionalColor(measurement, conditionalColoring) {
|
||||
if (measurement.value < conditionalColoring.threshold.poor) {
|
||||
return conditionalColoring.colors.poor;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ class DataTable extends React.PureComponent {
|
||||
const {
|
||||
headers: {
|
||||
dimension1,
|
||||
dimension2,
|
||||
measurements
|
||||
},
|
||||
matrix
|
||||
@@ -31,6 +32,58 @@ class DataTable extends React.PureComponent {
|
||||
maxWidth: columnSeparatorWidth
|
||||
};
|
||||
|
||||
const renderMeasurementData = (dimIndex, atEvery) => {
|
||||
const injectSeparatorsArray = injectSeparators(
|
||||
matrix[dimIndex],
|
||||
columnSeparatorWidth,
|
||||
atEvery
|
||||
);
|
||||
|
||||
if (dimension2.length <= 0) {
|
||||
return injectSeparatorsArray;
|
||||
}
|
||||
|
||||
const measurementDataRow = [];
|
||||
let index = 0,
|
||||
match;
|
||||
dimension2.forEach((dim2) => {
|
||||
measurements.forEach((measure, mesInd) => {
|
||||
for (index = 0; index < injectSeparatorsArray.length; index++) {
|
||||
match = false;
|
||||
if (injectSeparatorsArray[index].parents && dimension1[dimIndex].displayValue === injectSeparatorsArray[index].parents.dimension1.header) {
|
||||
if (dim2.displayValue === injectSeparatorsArray[index].parents.dimension2.header) {
|
||||
if (measure.name === injectSeparatorsArray[index].parents.measurement.header) {
|
||||
measurementDataRow.push(injectSeparatorsArray[index]);
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!match) {
|
||||
measurementDataRow.push({
|
||||
displayValue: '',
|
||||
parents: {
|
||||
dimension1: {
|
||||
elementNumber: dimension1[dimIndex].elementNumber,
|
||||
header: dimension1[dimIndex].displayValue
|
||||
},
|
||||
dimension2: {
|
||||
elementNumber: dim2.elementNumber,
|
||||
header: dim2.displayValue
|
||||
},
|
||||
measurement: {
|
||||
header: measure.name,
|
||||
index: mesInd
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
return measurementDataRow;
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="row-wrapper">
|
||||
<table>
|
||||
@@ -66,11 +119,7 @@ class DataTable extends React.PureComponent {
|
||||
styling={styling}
|
||||
/> : null
|
||||
}
|
||||
{renderData && injectSeparators(
|
||||
matrix[dimensionIndex],
|
||||
columnSeparatorWidth,
|
||||
{ atEvery: measurements.length }
|
||||
).map((measurementData, index) => {
|
||||
{renderData && renderMeasurementData(dimensionIndex, { atEvery: measurements.length }).map((measurementData, index) => {
|
||||
if (measurementData.isSeparator) {
|
||||
return (
|
||||
<td
|
||||
@@ -81,6 +130,7 @@ class DataTable extends React.PureComponent {
|
||||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-shadow
|
||||
const { dimension1: dimension1Info, dimension2, measurement } = measurementData.parents;
|
||||
const id = `${dimension1Info.elementNumber}-${dimension2 && dimension2.elementNumber}-${measurement.header}-${measurement.index}`;
|
||||
return (
|
||||
@@ -113,6 +163,7 @@ DataTable.defaultProps = {
|
||||
DataTable.propTypes = {
|
||||
cellWidth: PropTypes.string.isRequired,
|
||||
columnSeparatorWidth: PropTypes.string.isRequired,
|
||||
component: PropTypes.shape({}).isRequired,
|
||||
data: PropTypes.shape({
|
||||
headers: PropTypes.shape({
|
||||
dimension1: PropTypes.array.isRequired
|
||||
@@ -120,7 +171,6 @@ DataTable.propTypes = {
|
||||
matrix: PropTypes.arrayOf(PropTypes.array.isRequired).isRequired
|
||||
}).isRequired,
|
||||
general: PropTypes.shape({}).isRequired,
|
||||
component: PropTypes.shape({}).isRequired,
|
||||
renderData: PropTypes.bool,
|
||||
styling: PropTypes.shape({
|
||||
hasCustomFileStyle: PropTypes.bool.isRequired
|
||||
|
||||
@@ -10,9 +10,10 @@ class RowHeader extends React.PureComponent {
|
||||
this.handleSelect = this.handleSelect.bind(this);
|
||||
}
|
||||
|
||||
// fixes the console error on row selected values
|
||||
handleSelect () {
|
||||
const { component, entry } = this.props;
|
||||
component.backendApi.selectValues(0, [entry.elementNumber], false);
|
||||
component.selectValues(0, [entry.elementNumber], false);
|
||||
}
|
||||
|
||||
render () {
|
||||
@@ -42,13 +43,9 @@ class RowHeader extends React.PureComponent {
|
||||
}
|
||||
|
||||
RowHeader.propTypes = {
|
||||
entry: PropTypes.shape({
|
||||
displayValue: PropTypes.string.isRequired,
|
||||
elementNumber: PropTypes.number.isRequired
|
||||
}).isRequired,
|
||||
component: PropTypes.shape({
|
||||
backendApi: PropTypes.shape({
|
||||
selectValues: function (props, propName) {
|
||||
selectValues (props, propName) {
|
||||
if (props.isSnapshot || typeof props[propName] === 'function') {
|
||||
return null;
|
||||
}
|
||||
@@ -56,6 +53,10 @@ RowHeader.propTypes = {
|
||||
}
|
||||
}).isRequired
|
||||
}).isRequired,
|
||||
entry: PropTypes.shape({
|
||||
displayValue: PropTypes.string.isRequired,
|
||||
elementNumber: PropTypes.number.isRequired
|
||||
}).isRequired,
|
||||
rowStyle: PropTypes.shape({}).isRequired,
|
||||
styleBuilder: PropTypes.shape({}).isRequired,
|
||||
styling: PropTypes.shape({}).isRequired
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
/* eslint-disable object-shorthand */
|
||||
/* eslint-disable space-before-function-paren */
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { HEADER_FONT_SIZE } from '../initialize-transformed';
|
||||
import Tooltip from '../tooltip/index.jsx';
|
||||
|
||||
class ColumnHeader extends React.PureComponent {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.handleSelect = this.handleSelect.bind(this);
|
||||
}
|
||||
|
||||
handleSelect () {
|
||||
// fixes console error for column selected values
|
||||
handleSelect() {
|
||||
const { component, entry } = this.props;
|
||||
component.backendApi.selectValues(1, [entry.elementNumber], false);
|
||||
component.selectValues(1, [entry.elementNumber], false);
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
const { baseCSS, cellWidth, colSpan, component, entry, styling } = this.props;
|
||||
const inEditState = component.inEditState();
|
||||
const isMediumFontSize = styling.headerOptions.fontSizeAdjustment === HEADER_FONT_SIZE.MEDIUM;
|
||||
|
||||
@@ -36,6 +36,9 @@ export default {
|
||||
uses: 'measures'
|
||||
}
|
||||
},
|
||||
// Prevent conversion from and to this object
|
||||
exportProperties: null,
|
||||
importProperties: null,
|
||||
definition,
|
||||
initialProperties: {
|
||||
version: 1.0,
|
||||
@@ -50,7 +53,6 @@ export default {
|
||||
}
|
||||
],
|
||||
qMeasures: [],
|
||||
qSuppressMissing: true,
|
||||
qSuppressZero: false
|
||||
}
|
||||
},
|
||||
|
||||
@@ -64,7 +64,8 @@ function generateMatrixCell ({ cell, dimension1Information, dimension2Informatio
|
||||
|
||||
if (dimension2Information) {
|
||||
matrixCell.parents.dimension2 = {
|
||||
elementNumber: dimension2Information.qElemNumber
|
||||
elementNumber: dimension2Information.qElemNumber,
|
||||
header: dimension2Information.qText
|
||||
};
|
||||
}
|
||||
|
||||
@@ -126,30 +127,6 @@ function generateDataSet (component, dimensionsInformation, measurementsInformat
|
||||
dimension1 = distinctArray(dimension1);
|
||||
dimension2 = distinctArray(dimension2);
|
||||
|
||||
// Make sure all rows are saturated, otherwise data risks being displayed in the wrong column
|
||||
matrix = matrix.map((row, rowIndex) => {
|
||||
if ((hasSecondDimension && row.length == (dimension2.length * measurements.length))
|
||||
|| (!hasSecondDimension && row.length == measurements.length)) {
|
||||
// Row is saturated
|
||||
return row;
|
||||
}
|
||||
|
||||
// Row is not saturated, so must add empty cells to fill the gaps
|
||||
let newRow = [];
|
||||
if (hasSecondDimension) {
|
||||
// Got a second dimension, so need to add measurements for all values of the second dimension
|
||||
let rowDataIndex = 0;
|
||||
dimension2.forEach(dim => {
|
||||
rowDataIndex = appendMissingCells(
|
||||
row, newRow, rowDataIndex, measurements, rowIndex, dim.elementNumber);
|
||||
});
|
||||
} else {
|
||||
appendMissingCells(row, newRow, 0, measurements, rowIndex);
|
||||
}
|
||||
|
||||
return newRow;
|
||||
});
|
||||
|
||||
return {
|
||||
dimension1: dimension1,
|
||||
dimension2: dimension2,
|
||||
@@ -158,42 +135,6 @@ function generateDataSet (component, dimensionsInformation, measurementsInformat
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* Appends the cells of the source row, as well as those missing, to the destination row, starting
|
||||
* from the given source index. Returns the source index of the next source cell after this has
|
||||
* completed. If there is a second dimension the dim2ElementNumber should be set to the current
|
||||
* index of the dimension2 value being processed.
|
||||
*/
|
||||
function appendMissingCells (
|
||||
sourceRow, destRow, sourceIndex, measurements, dim1ElementNumber, dim2ElementNumber = -1) {
|
||||
|
||||
let index = sourceIndex;
|
||||
measurements.forEach((measurement, measureIndex) => {
|
||||
if (index < sourceRow.length
|
||||
&& (dim2ElementNumber === -1
|
||||
|| sourceRow[index].parents.dimension2.elementNumber === dim2ElementNumber)
|
||||
&& sourceRow[index].parents.measurement.header === measurement.name) {
|
||||
// Source contains the expected cell
|
||||
destRow.push(sourceRow[index]);
|
||||
index++;
|
||||
} else {
|
||||
// Source doesn't contain the expected cell, so add empty
|
||||
destRow.push({
|
||||
displayValue: '',
|
||||
parents: {
|
||||
dimension1: { elementNumber: dim1ElementNumber },
|
||||
dimension2: { elementNumber: dim2ElementNumber },
|
||||
measurement: {
|
||||
header: measurement.name,
|
||||
index: measureIndex
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return index;
|
||||
}
|
||||
|
||||
function initializeTransformed ({ component, dataCube, designList, layout }) {
|
||||
const dimensionsInformation = component.backendApi.getDimensionInfos();
|
||||
const measurementsInformation = component.backendApi.getMeasureInfos();
|
||||
|
||||
@@ -33,7 +33,7 @@ class LinkedScrollWrapper extends React.PureComponent {
|
||||
unlinkComponent (component) {
|
||||
const componentIndex = this.scrollElements.map(element => element.component).indexOf(component);
|
||||
if (componentIndex !== -1) {
|
||||
this.scrollElements.removeAt(componentIndex);
|
||||
this.scrollElements.splice(componentIndex, 1);
|
||||
// eslint-disable-next-line react/no-find-dom-node
|
||||
const node = ReactDOM.findDOMNode(component);
|
||||
node.onscroll = null;
|
||||
|
||||
11
src/root.jsx
11
src/root.jsx
@@ -12,9 +12,12 @@ class Root extends React.PureComponent {
|
||||
}
|
||||
|
||||
componentDidUpdate () {
|
||||
const tableWidth = this.dataTableRef.getBoundingClientRect().width;
|
||||
if (this.renderedTableWidth !== tableWidth) {
|
||||
this.forceUpdate();
|
||||
let tableWidth;
|
||||
if (this.dataTableRef) {
|
||||
tableWidth = this.dataTableRef.getBoundingClientRect().width;
|
||||
if (this.renderedTableWidth !== tableWidth) {
|
||||
this.forceUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +69,7 @@ class Root extends React.PureComponent {
|
||||
return (
|
||||
<div className="root">
|
||||
{error ? (
|
||||
<div className="error">
|
||||
<div className={`error ${editmodeClass}`}>
|
||||
{state.layout.errormessage}
|
||||
</div>
|
||||
) : (
|
||||
|
||||
Reference in New Issue
Block a user