Compare commits

...

9 Commits

Author SHA1 Message Date
Albert Backenhof
80f97602e4 Merge pull request #69 from qlik-oss/DEB-242/ExportInContainer
Excel export inside container
2019-05-27 14:36:31 +02:00
Albert Backenhof
f745656b4c Excel export inside container
-No tid-element available when inside native container.
 Therefore, use root element to find table cells instead.

Issue: DEB-242
2019-05-27 14:33:43 +02:00
Albert Backenhof
f7e780b92e Merge pull request #68 from qlik-oss/excelType
Specifying excel type of excel download
2019-05-27 14:28:26 +02:00
Albert Backenhof
d7a76c7db9 Merge pull request #63 from qlik-oss/QLIK-95802/AltStateFix
Fixed alternate state support
2019-05-27 14:26:58 +02:00
Albert Backenhof
16c380e1c6 Fixed alternate state support
-Previously, the shown data always followed
 default state, and not the set state.
-Previously, the selections made in smart pivot
 sometimes used the previous alternate state.

Issue: QLIK-95802
2019-05-27 14:24:02 +02:00
Albert Backenhof
072a3b80c4 Merge pull request #62 from qlik-oss/DEB-233/Selections
Handle selection toggle properly
2019-05-27 14:12:43 +02:00
Albert Backenhof
5572b7ce67 Merge pull request #64 from qlik-oss/DEB-221/WidthSlider
Slider for cell width without presets
2019-05-27 14:11:01 +02:00
Albert Backenhof
e26d5fded8 Specifying excel type of excel download 2019-05-20 10:12:22 +02:00
Albert Backenhof
729a31920d Handle selection toggle properly
-Previously, the cell selection would toggle
 the current selection. This meant, if a column
 is already selected when making a cell selection,
 the column selection would toggle off. With this
 fix the column selection stays on.

Issue: DEB-233
2019-05-13 09:43:41 +02:00
12 changed files with 85 additions and 81 deletions

View File

@@ -1,3 +1,4 @@
import qlik from 'qlik';
import React from 'react';
import PropTypes from 'prop-types';
import Tooltip from '../tooltip/index.jsx';
@@ -9,16 +10,33 @@ class DataCell extends React.PureComponent {
}
handleSelect () {
const { data: { meta: { dimensionCount } }, general: { allowFilteringByClick }, measurement, qlik } = this.props;
const {
data: {
headers,
meta: {
dimensionCount,
altState
}
},
general: {
allowFilteringByClick
},
measurement,
component
} = this.props;
const hasSecondDimension = dimensionCount > 1;
if (!allowFilteringByClick) {
return;
}
qlik.backendApi.selectValues(0, [measurement.parents.dimension1.elementNumber], true);
const app = qlik.currApp(component);
app.field(headers.dimension1[0].name, altState)
.select([measurement.parents.dimension1.elementNumber], false, false);
if (hasSecondDimension) {
qlik.backendApi.selectValues(1, [measurement.parents.dimension2.elementNumber], true);
app.field(headers.dimension2[0].name, altState)
.select([measurement.parents.dimension2.elementNumber], false, false);
}
}
@@ -88,7 +106,12 @@ class DataCell extends React.PureComponent {
DataCell.propTypes = {
data: PropTypes.shape({
headers: PropTypes.shape({
dimension1: PropTypes.array.isRequired,
measurements: PropTypes.array.isRequired
}).isRequired,
meta: PropTypes.shape({
altState: PropTypes.string.isRequired,
dimensionCount: PropTypes.number.isRequired
}).isRequired
}).isRequired,
general: PropTypes.shape({
@@ -99,16 +122,7 @@ DataCell.propTypes = {
name: PropTypes.string,
value: PropTypes.any
}).isRequired,
qlik: PropTypes.shape({
backendApi: PropTypes.shape({
selectValues: function (props, propName) {
if (props.isSnapshot || typeof props[propName] === 'function') {
return null;
}
return new Error('Missing implementation of qlik.backendApi.selectValues.');
}
}).isRequired
}).isRequired,
component: PropTypes.shape({}).isRequired,
styleBuilder: PropTypes.shape({
hasComments: PropTypes.func.isRequired
}).isRequired,

View File

@@ -5,7 +5,7 @@ import DataCell from './data-cell.jsx';
import RowHeader from './row-header.jsx';
import { injectSeparators } from '../utilities';
const DataTable = ({ data, general, qlik, renderData, styling }) => {
const DataTable = ({ data, general, component, renderData, styling }) => {
const {
headers: {
dimension1,
@@ -42,8 +42,9 @@ const DataTable = ({ data, general, qlik, renderData, styling }) => {
<tr key={dimensionEntry.displayValue}>
{!renderData ?
<RowHeader
altState={data.meta.altState}
entry={dimensionEntry}
qlik={qlik}
component={component}
rowStyle={rowStyle}
styleBuilder={styleBuilder}
styling={styling}
@@ -80,7 +81,7 @@ const DataTable = ({ data, general, qlik, renderData, styling }) => {
general={general}
key={`${dimensionEntry.displayValue}-${id}`}
measurement={measurementData}
qlik={qlik}
component={component}
styleBuilder={styleBuilder}
styling={styling}
/>
@@ -107,7 +108,7 @@ DataTable.propTypes = {
matrix: PropTypes.arrayOf(PropTypes.array.isRequired).isRequired
}).isRequired,
general: PropTypes.shape({}).isRequired,
qlik: PropTypes.shape({}).isRequired,
component: PropTypes.shape({}).isRequired,
renderData: PropTypes.bool,
styling: PropTypes.shape({
hasCustomFileStyle: PropTypes.bool.isRequired

View File

@@ -1,3 +1,4 @@
import qlik from 'qlik';
import React from 'react';
import PropTypes from 'prop-types';
import HeaderPadding from './header-padding.jsx';
@@ -11,13 +12,14 @@ class RowHeader extends React.PureComponent {
}
handleSelect () {
const { entry, qlik } = this.props;
qlik.backendApi.selectValues(0, [entry.elementNumber], true);
const { entry, altState, component } = this.props;
const app = qlik.currApp(component);
app.field(entry.name, altState).select([entry.elementNumber], false, false);
}
render () {
const { entry, rowStyle, styleBuilder, styling, qlik } = this.props;
const inEditState = qlik.inEditState();
const { entry, rowStyle, styleBuilder, styling, component } = this.props;
const inEditState = component.inEditState();
return (
<td
@@ -43,18 +45,12 @@ class RowHeader extends React.PureComponent {
RowHeader.propTypes = {
entry: PropTypes.shape({
displayValue: PropTypes.string.isRequired
}).isRequired,
qlik: PropTypes.shape({
backendApi: PropTypes.shape({
selectValues: function (props, propName) {
if (props.isSnapshot || typeof props[propName] === 'function') {
return null;
}
return new Error('Missing implementation of qlik.backendApi.selectValues.');
}
}).isRequired
displayValue: PropTypes.string.isRequired,
elementNumber: PropTypes.number.isRequired,
name: PropTypes.string.isRequired
}).isRequired,
altState: PropTypes.string.isRequired,
component: PropTypes.shape({}).isRequired,
rowStyle: PropTypes.shape({}).isRequired,
styleBuilder: PropTypes.shape({}).isRequired,
styling: PropTypes.shape({}).isRequired

View File

@@ -22,7 +22,9 @@ async function buildDataCube (originCubeDefinition, hasTwoDimensions, app) {
cubeDefinition.qDimensions.push(originCubeDefinition.qDimensions[1]);
}
const cube = await createCube(cubeDefinition, app);
return cube.qHyperCube.qDataPages[0].qMatrix;
const cubeMatrix = cube.qHyperCube.qDataPages[0].qMatrix;
app.destroySessionObject(cube.qInfo.qId);
return cubeMatrix;
}
export async function initializeDataCube (component, layout) {
@@ -37,6 +39,7 @@ export async function initializeDataCube (component, layout) {
const hyperCubeDef = properties.qExtendsId
? (await app.getObjectProperties(properties.qExtendsId)).properties.qHyperCubeDef
: properties.qHyperCubeDef;
hyperCubeDef.qStateName = layout.qStateName || "";
return buildDataCube(hyperCubeDef, layout.qHyperCube.qDimensionInfo.length === 2, app);
}

View File

@@ -7,13 +7,12 @@ function cleanupNodes (node) {
});
}
function buildTableHTML (id, title, subtitle, footnote) {
function buildTableHTML (containerElement, 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">${footnote}</p>`;
const container = document.querySelector(`[tid="${id}"]`);
const kpiTableClone = container.querySelector('.kpi-table').cloneNode(true);
const dataTableClone = container.querySelector('.data-table').cloneNode(true);
const kpiTableClone = containerElement[0].querySelector('.kpi-table').cloneNode(true);
const dataTableClone = containerElement[0].querySelector('.data-table').cloneNode(true);
cleanupNodes(kpiTableClone);
cleanupNodes(kpiTableClone);
@@ -83,7 +82,7 @@ function buildTableHTML (id, title, subtitle, footnote) {
function downloadXLS (html) {
const filename = 'analysis.xls';
const blobObject = new Blob([html]);
const blobObject = new Blob([html], { type: 'application/vnd.ms-excel' });
// IE/Edge
if (window.navigator.msSaveOrOpenBlob) {
@@ -100,8 +99,8 @@ function downloadXLS (html) {
return true;
}
export function exportXLS (id, title, subtitle, footnote) {
export function exportXLS (containerElement, 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(id, title, subtitle, footnote);
const table = buildTableHTML(containerElement, title, subtitle, footnote);
downloadXLS(table);
}

View File

@@ -9,10 +9,10 @@ class ExportButton extends React.PureComponent {
}
handleExport () {
const { id, excelExport, general } = this.props;
const { component, excelExport, general } = this.props;
const { title, subtitle, footnote } = general;
if (excelExport) {
exportXLS(id, title, subtitle, footnote);
exportXLS(component.$element, title, subtitle, footnote);
}
}
@@ -34,7 +34,7 @@ ExportButton.defaultProps = {
};
ExportButton.propTypes = {
id: PropTypes.string.isRequired,
component: PropTypes.shape({}).isRequired,
excelExport: PropTypes.bool,
general: PropTypes.shape({}).isRequired
};

View File

@@ -1,3 +1,4 @@
import qlik from 'qlik';
import React from 'react';
import PropTypes from 'prop-types';
import { HEADER_FONT_SIZE } from '../initialize-transformed';
@@ -10,13 +11,14 @@ class ColumnHeader extends React.PureComponent {
}
handleSelect () {
const { entry, qlik } = this.props;
qlik.backendApi.selectValues(1, [entry.elementNumber], true);
const { entry, altState, component } = this.props;
const app = qlik.currApp(component);
app.field(entry.name, altState).select([entry.elementNumber], false, false);
}
render () {
const { baseCSS, cellWidth, colSpan, entry, styling, qlik } = this.props;
const inEditState = qlik.inEditState();
const { baseCSS, cellWidth, colSpan, entry, styling, component } = this.props;
const inEditState = component.inEditState();
const isMediumFontSize = styling.headerOptions.fontSizeAdjustment === HEADER_FONT_SIZE.MEDIUM;
const style = {
@@ -56,19 +58,12 @@ ColumnHeader.propTypes = {
cellWidth: PropTypes.string,
colSpan: PropTypes.number,
entry: PropTypes.shape({
displayValue: PropTypes.string.isRequired,
elementNumber: PropTypes.number.isRequired,
name: PropTypes.string.isRequired
}).isRequired,
qlik: PropTypes.shape({
backendApi: PropTypes.shape({
selectValues: function (props, propName) {
if (props.isSnapshot || typeof props[propName] === 'function') {
return null;
}
return new Error('Missing implementation of qlik.backendApi.selectValues.');
}
}).isRequired
}).isRequired,
altState: PropTypes.string.isRequired,
component: PropTypes.shape({}).isRequired,
styling: PropTypes.shape({
headerOptions: PropTypes.shape({
fontSizeAdjustment: PropTypes.number.isRequired

View File

@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import ExportButton from '../export-button.jsx';
import { HEADER_FONT_SIZE } from '../initialize-transformed';
const ExportColumnHeader = ({ id, baseCSS, general, title, allowExcelExport, hasSecondDimension, styling }) => {
const ExportColumnHeader = ({ component, baseCSS, general, title, allowExcelExport, hasSecondDimension, styling }) => {
const rowSpan = hasSecondDimension ? 2 : 1;
const isMediumFontSize = styling.headerOptions.fontSizeAdjustment === HEADER_FONT_SIZE.MEDIUM;
const style = {
@@ -22,7 +22,7 @@ const ExportColumnHeader = ({ id, baseCSS, general, title, allowExcelExport, has
style={style}
>
<ExportButton
id={id}
component={component}
excelExport={allowExcelExport}
general={general}
/>
@@ -32,7 +32,7 @@ const ExportColumnHeader = ({ id, baseCSS, general, title, allowExcelExport, has
};
ExportColumnHeader.propTypes = {
id: PropTypes.string.isRequired,
component: PropTypes.shape({}).isRequired,
allowExcelExport: PropTypes.bool.isRequired,
baseCSS: PropTypes.shape({}).isRequired,
general: PropTypes.shape({}).isRequired,

View File

@@ -5,7 +5,7 @@ import ColumnHeader from './column-header.jsx';
import MeasurementColumnHeader from './measurement-column-header.jsx';
import { injectSeparators } from '../utilities';
const HeadersTable = ({ data, general, qlik, styling, isKpi }) => {
const HeadersTable = ({ data, general, component, styling, isKpi }) => {
const baseCSS = {
backgroundColor: styling.headerOptions.colorSchema,
color: styling.headerOptions.textColor,
@@ -28,7 +28,7 @@ const HeadersTable = ({ data, general, qlik, styling, isKpi }) => {
<tr>
{isKpi ?
<ExportColumnHeader
id={qlik.options.id}
component={component}
allowExcelExport={general.allowExcelExport}
baseCSS={baseCSS}
general={general}
@@ -67,12 +67,13 @@ const HeadersTable = ({ data, general, qlik, styling, isKpi }) => {
}
return (
<ColumnHeader
altState={data.meta.altState}
baseCSS={baseCSS}
cellWidth={general.cellWidth}
colSpan={measurements.length}
entry={entry}
key={entry.displayValue}
qlik={qlik}
component={component}
styling={styling}
/>
);
@@ -124,19 +125,13 @@ HeadersTable.propTypes = {
dimension1: PropTypes.array,
dimension2: PropTypes.array,
measurements: PropTypes.array
}),
meta: PropTypes.shape({
altState: PropTypes.string.isRequired
})
}).isRequired,
general: PropTypes.shape({}).isRequired,
qlik: PropTypes.shape({
backendApi: PropTypes.shape({
selectValues: function (props, propName) {
if (props.isSnapshot || typeof props[propName] === 'function') {
return null;
}
return new Error('Missing implementation of qlik.backendApi.selectValues.');
}
}).isRequired
}).isRequired,
component: PropTypes.shape({}).isRequired,
styling: PropTypes.shape({
headerOptions: PropTypes.shape({}),
options: PropTypes.shape({})

View File

@@ -71,7 +71,7 @@ export default {
const jsx = (
<Root
editmodeClass={editmodeClass}
qlik={this}
component={this}
state={state}
/>
);

View File

@@ -238,7 +238,8 @@ function initializeTransformed ({ $element, component, dataCube, designList, lay
},
matrix, // 2d array of all rows/cells to render in body of datatable
meta: {
dimensionCount: dimensionsInformation.length
dimensionCount: dimensionsInformation.length,
altState: layout.qStateName || ""
}
},
general: {

View File

@@ -4,7 +4,7 @@ import HeadersTable from './headers-table/index.jsx';
import DataTable from './data-table/index.jsx';
import { LinkedScrollWrapper, LinkedScrollSection } from './linked-scroll';
const Root = ({ state, qlik, editmodeClass }) => (
const Root = ({ state, component, editmodeClass }) => (
<div className="root">
<LinkedScrollWrapper>
<div className={`kpi-table ${editmodeClass}`}>
@@ -12,14 +12,14 @@ const Root = ({ state, qlik, editmodeClass }) => (
data={state.data}
general={state.general}
isKpi
qlik={qlik}
component={component}
styling={state.styling}
/>
<LinkedScrollSection linkVertical>
<DataTable
data={state.data}
general={state.general}
qlik={qlik}
component={component}
renderData={false}
styling={state.styling}
/>
@@ -31,7 +31,7 @@ const Root = ({ state, qlik, editmodeClass }) => (
data={state.data}
general={state.general}
isKpi={false}
qlik={qlik}
component={component}
styling={state.styling}
/>
</LinkedScrollSection>
@@ -42,7 +42,7 @@ const Root = ({ state, qlik, editmodeClass }) => (
<DataTable
data={state.data}
general={state.general}
qlik={qlik}
component={component}
styling={state.styling}
/>
</LinkedScrollSection>
@@ -52,7 +52,7 @@ const Root = ({ state, qlik, editmodeClass }) => (
);
Root.propTypes = {
qlik: PropTypes.shape({}).isRequired,
component: PropTypes.shape({}).isRequired,
state: PropTypes.shape({
data: PropTypes.object.isRequired,
general: PropTypes.object.isRequired,