Merge branch 'master' into QPE-426

This commit is contained in:
Balazs Gobel
2019-02-25 15:14:13 +01:00
committed by GitHub
9 changed files with 146 additions and 56 deletions

View File

@@ -117,7 +117,7 @@ module.exports = {
"max-params": ["warn"],
"brace-style": ["warn", "1tbs", { "allowSingleLine": true }],
"prefer-const": ["warn"],
"class-methods-use-this":["warn"],
// plugin:react
"react/jsx-indent": ["warn", 2],
"react/jsx-indent-props": ["warn", 2],
@@ -130,7 +130,8 @@ module.exports = {
"react/jsx-no-literals": ["off"],
"react/jsx-max-depth": ["off"], // rule throws exception in single-dimension-measure
"react/jsx-filename-extension": ["warn"],
"react/prefer-stateless-function": ["warn"]
"react/prefer-stateless-function": ["warn"],
"react/no-set-state": ["warn"]
},
extends: [
"eslint:all",

View File

@@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { ApplyPreMask } from '../masking';
import { addSeparators } from '../utilities';
import Tooltip from '../tooltip/index.jsx';
function formatMeasurementValue (measurement, styling) {
// TODO: measurement.name is a horrible propertyname, it's actually the column header
const isColumnPercentageBased = measurement.parents.measurement.header.substring(0, 1) === '%';
@@ -61,11 +61,9 @@ function getSemaphoreColors (measurement, semaphoreColors) {
}
return semaphoreColors.statusColors.normal;
}
class DataCell extends React.PureComponent {
constructor (props) {
super(props);
this.handleSelect = this.handleSelect.bind(this);
}
@@ -84,7 +82,14 @@ class DataCell extends React.PureComponent {
}
render () {
const { data, general, measurement, styleBuilder, styling } = this.props;
const {
data,
general,
measurement,
styleBuilder,
styling
} = this.props;
const isColumnPercentageBased = measurement.name.substring(0, 1) === '%';
let formattedMeasurementValue = formatMeasurementValue(measurement, styling);
if (styleBuilder.hasComments()) {
@@ -99,27 +104,29 @@ class DataCell extends React.PureComponent {
let cellStyle = {
fontFamily: styling.options.fontFamily,
...styleBuilder.getStyle(),
paddingLeft: '4px',
paddingLeft: '5px',
textAlign: textAlignment
};
const { semaphoreColors } = styling;
const { semaphoreColors, semaphoreColors: { fieldsToApplyTo } } = styling;
const isValidSemaphoreValue = !styleBuilder.hasComments() && !isNaN(measurement.value);
const shouldHaveSemaphoreColors = semaphoreColors.fieldsToApplyTo.applyToAll || semaphoreColors.fieldsToApplyTo.specificFields.indexOf(measurement.parents.dimension1.header) !== -1;
const shouldHaveSemaphoreColors = (fieldsToApplyTo.applyToMetric || fieldsToApplyTo.specificFields.indexOf(measurement.parents.dimension1.header) !== -1);
if (isValidSemaphoreValue && shouldHaveSemaphoreColors) {
const { backgroundColor, color } = getSemaphoreColors(measurement, semaphoreColors);
cellStyle = {
...styleBuilder.getStyle(),
backgroundColor,
color,
fontFamily: styling.options.fontFamily,
fontSize: styleBuilder.getStyle().fontSize,
paddingLeft: '4px',
paddingLeft: '5px',
textAlign: textAlignment
};
}
let cellClass = 'grid-cells';
const shouldUseSmallCells = isColumnPercentageBased && data.headers.measurements.length > 1;
const hasTwoDimensions = data.headers.dimension2 && data.headers.dimension2.length > 0;
const shouldUseSmallCells = isColumnPercentageBased && data.headers.measurements.length > 1 && hasTwoDimensions;
if (shouldUseSmallCells) {
cellClass = 'grid-cells-small';
}
@@ -130,12 +137,15 @@ class DataCell extends React.PureComponent {
onClick={this.handleSelect}
style={cellStyle}
>
{formattedMeasurementValue}
<Tooltip
tooltipText={formattedMeasurementValue}
>
{formattedMeasurementValue}
</Tooltip>
</td>
);
}
}
DataCell.propTypes = {
data: PropTypes.shape({
headers: PropTypes.shape({

View File

@@ -1,10 +1,10 @@
import React from 'react';
import PropTypes from 'prop-types';
import Tooltip from '../tooltip/index.jsx';
class ColumnHeader extends React.PureComponent {
constructor (props) {
super(props);
this.handleSelect = this.handleSelect.bind(this);
}
@@ -14,7 +14,9 @@ class ColumnHeader extends React.PureComponent {
}
render () {
const { baseCSS, cellSuffix, colSpan, entry, styling } = this.props;
const { baseCSS, cellSuffix, colSpan, entry, styling, qlik } = this.props;
const inEditState = qlik.inEditState();
const style = {
...baseCSS,
fontSize: `${14 + styling.headerOptions.fontSizeAdjustment} px`,
@@ -29,7 +31,12 @@ class ColumnHeader extends React.PureComponent {
onClick={this.handleSelect}
style={style}
>
{entry.displayValue}
<Tooltip
isTooltipActive={!inEditState}
tooltipText={entry.displayValue}
>
{entry.displayValue}
</Tooltip>
</th>
);
}

View File

@@ -13,7 +13,8 @@ describe('<HeadersTable />', () => {
qlik: {
backendApi: {
selectValues: () => {}
}
},
inEditState: () => {}
},
styling
};

View File

@@ -260,6 +260,7 @@ async function initializeTransformed ({ $element, layout, component }) {
semaphoreColors: {
fieldsToApplyTo: {
applyToAll: layout.allsemaphores,
applyToMetric: layout.allmetrics,
specificFields: [
layout.conceptsemaphore1,
layout.conceptsemaphore2,

View File

@@ -3,6 +3,12 @@
@TableBorder: 1px solid #d3d3d3;
@KpiTableWidth: 230px;
*,
*::before,
*::after {
box-sizing: border-box;
}
.edit-mode {
pointer-events: none;
}
@@ -18,6 +24,38 @@
z-index: 110;
}
.tooltip-wrapper {
min-width: 25px;
position: fixed;
padding: 5px;
padding-top: 15px;
background-color: #404040;
z-index: 100;
pointer-events: none;
border-radius: 5px;
height: 30px;
width: auto;
opacity: 0.9;
text-align: center;
transform: translate(-50%, -110%);
> p {
color: #fff;
}
}
.tooltip-wrapper::after {
content: "";
position: absolute;
bottom: -10px;
left: 50%;
border-width: 10px 10px 0;
border-style: solid;
border-color: #404040 transparent;
margin-left: -10px;
pointer-events: none;
}
.icon-xls {
text-align: left;
}
@@ -102,6 +140,7 @@
/* ***************** */
.grid-cells {
position: relative;
._cell(70px);
}
@@ -198,13 +237,6 @@
width: 350px;
}
/* popups for headers */
.header-wrapper {
position: absolute;
top: 0;
z-index: 1;
}
.tooltip {
position: fixed !important;
color: rgb(70, 70, 70);
@@ -213,12 +245,6 @@
border: groove;
}
.row-wrapper {
height: calc(~"100% - 97px");
padding: 0;
margin-top: 0;
}
.kpi-table .fdim-cells,
.data-table td {
line-height: 1em !important;
@@ -274,6 +300,8 @@
.kpi-table .row-wrapper,
.data-table .header-wrapper,
.data-table .row-wrapper {
/* stylelint-disable-next-line property-no-unknown */
scrollbar-width: none;
-ms-overflow-style: none; // IE 10+
-moz-overflow: -moz-scrollbars-none; // Firefox

View File

@@ -1,4 +1,3 @@
import $ from 'jquery'; // eslint-disable-line id-length
import initializeStore from './store';
import React from 'react';
import ReactDOM from 'react-dom';
@@ -20,27 +19,4 @@ export default async function paint ($element, layout, component) {
);
ReactDOM.render(jsx, $element[0]);
// TODO: fixing tooltips has a seperate issue, make sure to remove this as part of that issue
$(`[tid="${layout.qInfo.qId}"] .header-wrapper th`).hover(function () {
$(`[tid="${layout.qInfo.qId}"] .tooltip`).delay(500)
.show(0);
$(`[tid="${layout.qInfo.qId}"] .header-wrapper th`).children(`[tid="${layout.qInfo.qId}"] .tooltip`)
.remove();
const element = $(this);
const offset = element.offset();
const toolTip = $('<div class="tooltip"></div>');
toolTip.css({
left: offset.left,
top: offset.top
});
toolTip.text(element.text());
$(`[tid="${layout.qInfo.qId}"] .header-wrapper th`).append(toolTip);
}, () => {
$(`[tid="${layout.qInfo.qId}"] .tooltip`).delay(0)
.hide(0);
});
}

View File

@@ -10,7 +10,8 @@ describe('<Root />', () => {
qlik: {
backendApi: {
selectValues: () => {}
}
},
inEditState: () => {}
},
state
};

65
src/tooltip/index.jsx Normal file
View File

@@ -0,0 +1,65 @@
import React from 'react';
import PropTypes from 'prop-types';
const handleCalculateTooltipPosition = (event) => {
const tooltipClassName = 'tooltip-wrapper';
const tooltip = document.getElementsByClassName(tooltipClassName);
tooltip[0].style.left = event.clientX + 'px';
tooltip[0].style.top = event.clientY + 'px';
};
class Tooltip extends React.Component {
constructor (props) {
super(props);
this.state = {
showTooltip: false
};
this.handleRenderTooltip = this.handleRenderTooltip.bind(this);
}
shouldComponentUpdate (nextProps, nextState) {
const { showTooltip } = this.state;
if (nextState.showTooltip === showTooltip) {
return false;
}
return true;
}
handleRenderTooltip () {
const { showTooltip } = this.state;
this.setState({ showTooltip: !showTooltip });
}
render () {
const { children, tooltipText } = this.props;
const { showTooltip } = this.state;
return (
<div
onMouseMove={handleCalculateTooltipPosition}
onMouseOut={this.handleRenderTooltip}
onMouseOver={this.handleRenderTooltip}
>
{children}
{showTooltip
? (
<div
className="tooltip-wrapper"
>
<p>
{tooltipText}
</p>
</div>
) : null}
</div>
);
}
}
Tooltip.propTypes = {
children: PropTypes.string.isRequired,
tooltipText: PropTypes.string.isRequired
};
export default Tooltip;