Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44b33b4c92 | ||
|
|
61b339b146 | ||
|
|
fc363d7739 | ||
|
|
35d4dde118 | ||
|
|
e70e76a401 | ||
|
|
34477d7ef1 | ||
|
|
b65d1c51fc | ||
|
|
9111ec762b | ||
|
|
b86806d4cd | ||
|
|
c3651a37da | ||
|
|
8b843e028a |
@@ -18,6 +18,14 @@ jobs:
|
||||
- run:
|
||||
name: Install dependencies
|
||||
command: npm install
|
||||
- run:
|
||||
name: BlackDuck scan
|
||||
command: curl -s https://blackducksoftware.github.io/hub-detect/hub-detect.sh | bash -s -- \
|
||||
--blackduck.url="https://qliktech.blackducksoftware.com" \
|
||||
--blackduck.trust.cert=true \
|
||||
--blackduck.username="svc-blackduck" \
|
||||
--blackduck.password=${svc_blackduck} \
|
||||
--detect.project.name="viz-bundle-qlik-smart-pivot"
|
||||
- run:
|
||||
name: Run tests
|
||||
command: npm run test-once
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Smart pivot",
|
||||
"description": "Formatted table for P&L reports.",
|
||||
"name": "P&L pivot",
|
||||
"description": "Profit & Loss reporting with color and font customizations.",
|
||||
"type": "visualization",
|
||||
"version": "X.Y.Z",
|
||||
"icon": "table",
|
||||
|
||||
@@ -139,6 +139,10 @@ const formatted = {
|
||||
component: 'dropdown',
|
||||
label: 'FontFamily',
|
||||
options: [
|
||||
{
|
||||
value: 'QlikView Sans',
|
||||
label: 'QlikView Sans'
|
||||
},
|
||||
{
|
||||
value: 'Arial',
|
||||
label: 'Arial'
|
||||
@@ -164,7 +168,7 @@ const formatted = {
|
||||
label: 'Verdana'
|
||||
}
|
||||
],
|
||||
defaultValue: 'Calibri'
|
||||
defaultValue: 'QlikView Sans'
|
||||
},
|
||||
DataFontSize: {
|
||||
ref: 'lettersize',
|
||||
@@ -181,7 +185,7 @@ const formatted = {
|
||||
label: 'Medium'
|
||||
}
|
||||
],
|
||||
defaultValue: 2
|
||||
defaultValue: 1
|
||||
},
|
||||
ColumnWidthSlider: {
|
||||
type: 'number',
|
||||
|
||||
@@ -1,73 +1,86 @@
|
||||
import $ from 'jquery';
|
||||
|
||||
const isIE = /* @cc_on!@*/false || Boolean(document.documentMode);
|
||||
const isChrome = Boolean(window.chrome) && Boolean(window.chrome.webstore);
|
||||
const isSafari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0;
|
||||
const isFirefox = typeof InstallTrigger !== 'undefined';
|
||||
|
||||
export function enableExcelExport (layout, f) {
|
||||
let myTitle = '';
|
||||
let mySubTitle = '';
|
||||
let myFootNote = '';
|
||||
if (layout.title.length > 0) {
|
||||
myTitle += '<p style="font-size:15pt"><b>';
|
||||
myTitle += layout.title;
|
||||
myTitle += '</b></p>';
|
||||
}
|
||||
if (layout.subtitle.length > 0) {
|
||||
mySubTitle += '<p style="font-size:11pt">';
|
||||
mySubTitle += layout.subtitle;
|
||||
mySubTitle += '</p>';
|
||||
}
|
||||
if (layout.footnote.length > 0) {
|
||||
myFootNote += '<p style="font-size:11pt"><i>Note:</i>';
|
||||
myFootNote += layout.footnote;
|
||||
myFootNote += '</p>';
|
||||
}
|
||||
|
||||
$('.icon-xls').on('click', () => {
|
||||
$('.header-wrapper th').children('.tooltip')
|
||||
.remove(); // remove some popup effects when exporting
|
||||
$('.header-wrapper th').children('.icon-xls')
|
||||
.remove(); // remove the xls icon when exporting
|
||||
if (isChrome || isSafari) {
|
||||
const $clonedDiv = $('.data-table').clone(true); // .kpi-table a secas exporta la 1ªcol
|
||||
let vEncodeHead = '<html><head><meta charset="UTF-8"></head>';
|
||||
vEncodeHead += myTitle + mySubTitle + myFootNote;
|
||||
const vEncode = encodeURIComponent($clonedDiv.html());
|
||||
let vDecode = `${vEncodeHead + vEncode}</html>`;
|
||||
|
||||
$clonedDiv.find('tr.header');
|
||||
vDecode = vDecode.split('%3E.%3C').join('%3E%3C');
|
||||
window.open(`data:application/vnd.ms-excel,${vDecode}`);
|
||||
$.preventDefault();
|
||||
}
|
||||
if (isIE) {
|
||||
let a = '<html><head><meta charset="UTF-8"></head>';
|
||||
a += myTitle + mySubTitle + myFootNote;
|
||||
a += f;
|
||||
a = a.split('>.<').join('><');
|
||||
a += '</html>';
|
||||
|
||||
const w = window.open();
|
||||
w.document.open();
|
||||
w.document.write(a);
|
||||
w.document.close();
|
||||
w.document.execCommand('SaveAs', true, 'Analysis.xls' || 'c:\TMP');
|
||||
w.close();
|
||||
}
|
||||
|
||||
if (isFirefox) {
|
||||
const $clonedDiv = $('.data-table').clone(true);// .kpi-table a secas exporta la 1ªcol
|
||||
let vEncodeHead = '<html><head><meta charset="UTF-8"></head>';
|
||||
vEncodeHead += myTitle + mySubTitle + myFootNote;
|
||||
const vEncode = encodeURIComponent($clonedDiv.html());
|
||||
let vDecode = `${vEncodeHead + vEncode}</html>`;
|
||||
|
||||
$clonedDiv.find('tr.header');
|
||||
vDecode = vDecode.split('>.<').join('><');
|
||||
window.open(`data:application/vnd.ms-excel,${vDecode}`);
|
||||
$.preventDefault();
|
||||
function removeAllTooltips (node) {
|
||||
const tooltips = node.querySelectorAll('.tooltip');
|
||||
[].forEach.call(tooltips, tooltip => {
|
||||
if (tooltip.parentNode) {
|
||||
tooltip.parentNode.removeChild(tooltip);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function buildTableHTML (title, subtitle, footnote) {
|
||||
const titleHTML = `<p style="font-size:15pt"><b>${title}</b></p>`;
|
||||
const subtitleHTML = `<p style="font-size:11pt">${subtitle}</p>`;
|
||||
const footnoteHTML = `<p style="font-size:11pt"><i>Note:</i>${footnote}</p>`;
|
||||
const dataTableClone = document.querySelector('.data-table').cloneNode(true);
|
||||
|
||||
removeAllTooltips(dataTableClone);
|
||||
|
||||
const tableHTML = `
|
||||
<html
|
||||
xmlns:o="urn:schemas-microsoft-com:office:office"
|
||||
xmlns:x="urn:schemas-microsoft-com:office:excel"
|
||||
xmlns="http://www.w3.org/TR/REC-html40"
|
||||
>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<!--[if gte mso 9]>
|
||||
<xml>
|
||||
<x:ExcelWorkbook>
|
||||
<x:ExcelWorksheets>
|
||||
<x:ExcelWorksheet>
|
||||
<x:Name>${title || 'Analyze'}</x:Name>
|
||||
<x:WorksheetOptions>
|
||||
<x:DisplayGridlines/>
|
||||
</x:WorksheetOptions>
|
||||
</x:ExcelWorksheet>
|
||||
</x:ExcelWorksheets>
|
||||
</x:ExcelWorkbook>
|
||||
</xml>
|
||||
<![endif]-->
|
||||
</head>
|
||||
<body>
|
||||
${titleHTML.length > 0 ? titleHTML : ''}
|
||||
${subtitleHTML.length > 0 ? subtitleHTML : ''}
|
||||
${footnoteHTML.length > 0 ? footnoteHTML : ''}
|
||||
${dataTableClone.outerHTML}
|
||||
</body>
|
||||
</html>
|
||||
`.split('>.<')
|
||||
.join('><')
|
||||
.split('>*<')
|
||||
.join('><');
|
||||
|
||||
return tableHTML;
|
||||
}
|
||||
|
||||
function downloadXLS (html) {
|
||||
const filename = 'analysis.xls';
|
||||
// IE/Edge
|
||||
if (window.navigator.msSaveOrOpenBlob) {
|
||||
const blobObject = new Blob([html]);
|
||||
return window.navigator.msSaveOrOpenBlob(blobObject, filename);
|
||||
}
|
||||
|
||||
const dataURI = generateDataURI(html);
|
||||
const link = window.document.createElement('a');
|
||||
link.href = dataURI;
|
||||
link.download = filename;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function generateDataURI (html) {
|
||||
const dataType = 'data:application/vnd.ms-excel;base64,';
|
||||
const data = window.btoa(unescape(encodeURIComponent(html)));
|
||||
|
||||
return `${dataType}${data}`;
|
||||
}
|
||||
|
||||
export function exportXLS (title, subtitle, footnote) {
|
||||
// original was removing icon when starting export, disable and some spinner instead, shouldn't take enough time to warrant either..?
|
||||
const table = buildTableHTML(title, subtitle, footnote);
|
||||
downloadXLS(table);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,27 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { exportXLS } from './excel-export';
|
||||
|
||||
// TODO: move interaction logic in here from excel-export.js
|
||||
class ExportButton extends React.PureComponent {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.handleExport = this.handleExport.bind(this);
|
||||
}
|
||||
|
||||
handleExport () {
|
||||
const { excelExport, general } = this.props;
|
||||
const { title, subtitle, footnote } = general;
|
||||
if (excelExport) {
|
||||
exportXLS(title, subtitle, footnote);
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
const { excelExport } = this.props;
|
||||
return excelExport === true && (
|
||||
<input
|
||||
className="icon-xls"
|
||||
onClick={this.handleExport}
|
||||
src="/Extensions/qlik-smart-pivot/Excel.png"
|
||||
type="image"
|
||||
/>
|
||||
@@ -20,7 +34,8 @@ ExportButton.defaultProps = {
|
||||
};
|
||||
|
||||
ExportButton.propTypes = {
|
||||
excelExport: PropTypes.bool
|
||||
excelExport: PropTypes.bool,
|
||||
general: PropTypes.shape({}).isRequired
|
||||
};
|
||||
|
||||
export default ExportButton;
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ExportButton from '../export-button.jsx';
|
||||
|
||||
const ExportColumnHeader = ({ baseCSS, title, allowExcelExport, hasSecondDimension, styling }) => {
|
||||
const ExportColumnHeader = ({ baseCSS, general, title, allowExcelExport, hasSecondDimension, styling }) => {
|
||||
const rowSpan = hasSecondDimension ? 2 : 1;
|
||||
const style = {
|
||||
...baseCSS,
|
||||
@@ -19,7 +19,10 @@ const ExportColumnHeader = ({ baseCSS, title, allowExcelExport, hasSecondDimensi
|
||||
rowSpan={rowSpan}
|
||||
style={style}
|
||||
>
|
||||
<ExportButton excelExport={allowExcelExport} />
|
||||
<ExportButton
|
||||
excelExport={allowExcelExport}
|
||||
general={general}
|
||||
/>
|
||||
{title}
|
||||
</th>
|
||||
);
|
||||
@@ -28,6 +31,7 @@ const ExportColumnHeader = ({ baseCSS, title, allowExcelExport, hasSecondDimensi
|
||||
ExportColumnHeader.propTypes = {
|
||||
allowExcelExport: PropTypes.bool.isRequired,
|
||||
baseCSS: PropTypes.shape({}).isRequired,
|
||||
general: PropTypes.shape({}).isRequired,
|
||||
hasSecondDimension: PropTypes.bool.isRequired,
|
||||
styling: PropTypes.shape({
|
||||
headerOptions: PropTypes.shape({
|
||||
|
||||
@@ -29,6 +29,7 @@ const HeadersTable = ({ data, general, qlik, styling }) => {
|
||||
<ExportColumnHeader
|
||||
allowExcelExport={general.allowExcelExport}
|
||||
baseCSS={baseCSS}
|
||||
general={general}
|
||||
hasSecondDimension={hasSecondDimension}
|
||||
styling={styling}
|
||||
title={dimension1[0].name}
|
||||
|
||||
@@ -25,6 +25,11 @@ export default {
|
||||
qMeasures: []
|
||||
}
|
||||
},
|
||||
support: {
|
||||
export: true,
|
||||
exportData: true,
|
||||
snapshot: true
|
||||
},
|
||||
paint ($element, layout) {
|
||||
try {
|
||||
paint($element, layout, this);
|
||||
|
||||
@@ -39,8 +39,8 @@ function getAlignment (option) {
|
||||
|
||||
function getFontSizeAdjustment (option) {
|
||||
const fontSizeAdjustmentOptions = {
|
||||
1: -2,
|
||||
2: 0,
|
||||
1: -1,
|
||||
2: 1,
|
||||
3: 2
|
||||
};
|
||||
|
||||
@@ -255,7 +255,10 @@ async function initializeTransformed ({ $element, layout, component }) {
|
||||
allowFilteringByClick: layout.filteroncellclick,
|
||||
cellSuffix: getCellSuffix(layout.columnwidthslider), // TOOD: move to matrix cells or is it headers.measurements?
|
||||
errorMessage: layout.errormessage,
|
||||
maxLoops
|
||||
footnote: layout.footnote,
|
||||
maxLoops,
|
||||
subtitle: layout.subtitle,
|
||||
title: layout.title
|
||||
},
|
||||
selection: {
|
||||
dimensionSelectionCounts: dimensionsInformation.map(dimensionInfo => dimensionInfo.qStateCounts.qSelected)
|
||||
|
||||
@@ -48,7 +48,6 @@ export default async function paint ($element, layout, component) {
|
||||
|
||||
ReactDOM.render(jsx, $element[0]);
|
||||
|
||||
|
||||
// TODO: skipped the following as they weren't blockers for letting react handle rendering,
|
||||
// they are however the only reason we still depend on jQuery and should be removed as part of unnecessary dependencies issue
|
||||
$(`[tid="${layout.qInfo.qId}"] .data-table .row-wrapper`).on('scroll', function () {
|
||||
@@ -82,8 +81,4 @@ export default async function paint ($element, layout, component) {
|
||||
$(`[tid="${layout.qInfo.qId}"] .tooltip`).delay(0)
|
||||
.hide(0);
|
||||
});
|
||||
|
||||
// TODO: excel export is broken in most browsers, fixing it has an issue of it's own (leaving it disabled for now)
|
||||
// import { enableExcelExport } from './excel-export';
|
||||
// enableExcelExport(layout, html);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user