diff --git a/.eslintrc.js b/.eslintrc.js
index 8944cac..d51b712 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -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",
diff --git a/src/data-table/data-cell.jsx b/src/data-table/data-cell.jsx
index d176fc8..f137a03 100644
--- a/src/data-table/data-cell.jsx
+++ b/src/data-table/data-cell.jsx
@@ -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}
+
+ {formattedMeasurementValue}
+
);
}
}
-
DataCell.propTypes = {
data: PropTypes.shape({
headers: PropTypes.shape({
diff --git a/src/headers-table/column-header.jsx b/src/headers-table/column-header.jsx
index d50d666..e698a82 100644
--- a/src/headers-table/column-header.jsx
+++ b/src/headers-table/column-header.jsx
@@ -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}
+
+ {entry.displayValue}
+
);
}
diff --git a/src/headers-table/index.spec.js b/src/headers-table/index.spec.js
index 9c7cb27..c2458a5 100644
--- a/src/headers-table/index.spec.js
+++ b/src/headers-table/index.spec.js
@@ -13,7 +13,8 @@ describe('', () => {
qlik: {
backendApi: {
selectValues: () => {}
- }
+ },
+ inEditState: () => {}
},
styling
};
diff --git a/src/initialize-transformed.js b/src/initialize-transformed.js
index 1e1f063..04084ce 100644
--- a/src/initialize-transformed.js
+++ b/src/initialize-transformed.js
@@ -260,6 +260,7 @@ async function initializeTransformed ({ $element, layout, component }) {
semaphoreColors: {
fieldsToApplyTo: {
applyToAll: layout.allsemaphores,
+ applyToMetric: layout.allmetrics,
specificFields: [
layout.conceptsemaphore1,
layout.conceptsemaphore2,
diff --git a/src/main.less b/src/main.less
index ee5dbd9..ac01c42 100644
--- a/src/main.less
+++ b/src/main.less
@@ -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
diff --git a/src/paint.jsx b/src/paint.jsx
index 6d9fe26..50586f4 100644
--- a/src/paint.jsx
+++ b/src/paint.jsx
@@ -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 = $('
');
-
- 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);
- });
}
diff --git a/src/root.spec.js b/src/root.spec.js
index 42214c9..6cf20e9 100644
--- a/src/root.spec.js
+++ b/src/root.spec.js
@@ -10,7 +10,8 @@ describe('', () => {
qlik: {
backendApi: {
selectValues: () => {}
- }
+ },
+ inEditState: () => {}
},
state
};
diff --git a/src/tooltip/index.jsx b/src/tooltip/index.jsx
new file mode 100644
index 0000000..336c6a1
--- /dev/null
+++ b/src/tooltip/index.jsx
@@ -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 (
+
+ {children}
+
+ {showTooltip
+ ? (
+
+ ) : null}
+
+ );
+ }
+}
+
+Tooltip.propTypes = {
+ children: PropTypes.string.isRequired,
+ tooltipText: PropTypes.string.isRequired
+};
+export default Tooltip;