From fd9e645fc1935adec01fcfb1a655f44c6286903a Mon Sep 17 00:00:00 2001 From: Purwa Shrivastava Date: Thu, 21 Nov 2019 10:59:28 +0100 Subject: [PATCH] Pivot Pagination Fix. --- src/data-table/index.jsx | 1 + src/dataset.js | 33 +++++++-- src/definition/pagination.js | 27 +------- src/index.js | 100 +++++++++++++++++----------- src/initialize-transformed.js | 95 +++++++++++--------------- src/main.less | 14 ++++ src/root.jsx | 122 ++++++++++++++++++---------------- 7 files changed, 210 insertions(+), 182 deletions(-) diff --git a/src/data-table/index.jsx b/src/data-table/index.jsx index f804a30..afff2bd 100644 --- a/src/data-table/index.jsx +++ b/src/data-table/index.jsx @@ -5,6 +5,7 @@ import DataCell from './data-cell.jsx'; import RowHeader from './row-header.jsx'; import { injectSeparators } from '../utilities'; +// eslint-disable-next-line react/prefer-stateless-function class DataTable extends React.PureComponent { render () { const { diff --git a/src/dataset.js b/src/dataset.js index 27fcf7f..29859d1 100644 --- a/src/dataset.js +++ b/src/dataset.js @@ -6,12 +6,15 @@ function createCube (definition, app) { }); } -async function buildDataCube (originCubeDefinition, originCube, app) { +async function buildDataCube (originCubeDefinition, originCube, app, requestPage) { const cubeDefinition = { ...originCubeDefinition, qInitialDataFetch: [ { - qHeight: originCube.qSize.qcy, + // eslint-disable-next-line no-undefined + qTop: requestPage === undefined ? 0 : requestPage[0].qTop, + qLeft: 0, + qHeight: 1000, qWidth: originCube.qSize.qcx } ], @@ -28,12 +31,15 @@ async function buildDataCube (originCubeDefinition, originCube, app) { } export async function initializeDataCube (component, layout) { + if (component.backendApi.isSnapshot) { return layout.snapshotData.dataCube; } - const app = qlik.currApp(component); const properties = (await component.backendApi.getProperties()); + const rowCount = component.backendApi.getRowCount(); + const cellCount = rowCount * layout.qHyperCube.qSize.qcx; + const maxLoops = layout.maxloops; // If this is a master object, fetch the hyperCubeDef of the original object let hyperCubeDef = properties.qExtendsId @@ -41,8 +47,25 @@ export async function initializeDataCube (component, layout) { : properties.qHyperCubeDef; hyperCubeDef = JSON.parse(JSON.stringify(hyperCubeDef)); hyperCubeDef.qStateName = layout.qStateName; - - return buildDataCube(hyperCubeDef, layout.qHyperCube, app); + const pagedCube = {}; + let lastRow = 0; + if (cellCount < (maxLoops * 10000)) { + for (let index = 0; cellCount > lastRow; index += 1) { + const requestPage = [ + { + qHeight: 1000, + qLeft: 0, + qTop: lastRow, + qWidth: 10 // should be # of columns + } + ]; + // eslint-disable-next-line no-await-in-loop + pagedCube[index] = await buildDataCube(hyperCubeDef, layout.qHyperCube, app, requestPage); + lastRow = lastRow + 1000; + } + return pagedCube; + } + return null; } export function initializeDesignList (component, layout) { diff --git a/src/definition/pagination.js b/src/definition/pagination.js index 0568f1e..3b05b19 100644 --- a/src/definition/pagination.js +++ b/src/definition/pagination.js @@ -23,30 +23,6 @@ const pagination = { { value: 4, label: '40k cells' - }, - { - value: 5, - label: '50k cells' - }, - { - value: 6, - label: '60k cells' - }, - { - value: 7, - label: '70k cells' - }, - { - value: 8, - label: '80k cells' - }, - { - value: 9, - label: '90k cells' - }, - { - value: 10, - label: '100k cells' } ], defaultValue: 2 @@ -55,7 +31,8 @@ const pagination = { ref: 'errormessage', label: 'Default error message', type: 'string', - defaultValue: 'Unable to display all the data. Apply more filters to limit the amount of displayed data.' + defaultValue: `Unable to display all the data. + Change the pagination size supported or apply more filters to limit the amount of displayed data.` } } }; diff --git a/src/index.js b/src/index.js index b7a6d46..f0fcb8a 100644 --- a/src/index.js +++ b/src/index.js @@ -1,15 +1,16 @@ -import definition from './definition'; -import { exportXLS } from './excel-export'; -import { initializeDataCube, initializeDesignList } from './dataset'; -import initializeStore from './store'; -import qlik from 'qlik'; -import React from 'react'; -import ReactDOM from 'react-dom'; -import Root from './root.jsx'; -import './main.less'; +import definition from "./definition"; +import { exportXLS } from "./excel-export"; +import { initializeDataCube, initializeDesignList } from "./dataset"; +import initializeStore from "./store"; +import qlik from "qlik"; +import React from "react"; +import ReactDOM from "react-dom"; +import Root from "./root.jsx"; +import "./main.less"; -if (!window._babelPolyfill) { // eslint-disable-line no-underscore-dangle - require('@babel/polyfill'); // eslint-disable-line global-require +if (!window._babelPolyfill) { + // eslint-disable-line no-underscore-dangle + require("@babel/polyfill"); // eslint-disable-line global-require } export default { @@ -21,14 +22,14 @@ export default { }, data: { dimensions: { - max: function (nMeasures) { + max (nMeasures) { return nMeasures < 9 ? 2 : 1; }, min: 1, uses: 'dimensions' }, measures: { - max: function (nDims) { + max (nDims) { return nDims < 2 ? 9 : 8; }, min: 1, @@ -42,8 +43,10 @@ export default { qDimensions: [], qInitialDataFetch: [ { - qHeight: 1, - qWidth: 10 + qTop: 0, + qLeft: 0, + qWidth: 50, + qHeight: 50 } ], qMeasures: [], @@ -56,23 +59,32 @@ export default { exportData: true, snapshot: true }, - paint: async function ($element, layout) { - const dataCube = await initializeDataCube(this, layout); - const designList = await initializeDesignList(this, layout); - const state = await initializeStore({ - $element, - component: this, - dataCube, - designList, - layout - }); + async paint ($element, layout, requestPage) { + const dataCube = await initializeDataCube(this, layout, requestPage); const editmodeClass = this.inAnalysisState() ? '' : 'edit-mode'; + let state, designList; + if (dataCube === null) { + state = { + $element, + component: this, + dataCube, + designList, + layout, + error: true + }; + } else { + designList = await initializeDesignList(this, layout); + state = await initializeStore({ + $element, + component: this, + dataCube, + designList, + layout, + error: false + }); + } const jsx = ( - + ); ReactDOM.render(jsx, $element[0]); @@ -80,28 +92,38 @@ export default { snapshot: { canTakeSnapshot: true }, - setSnapshotData: async function (snapshotLayout) { - snapshotLayout.snapshotData.dataCube = await initializeDataCube(this, snapshotLayout); - snapshotLayout.snapshotData.designList = await initializeDesignList(this, snapshotLayout); + async setSnapshotData (snapshotLayout) { + snapshotLayout.snapshotData.dataCube = await initializeDataCube( + this, + snapshotLayout + ); + snapshotLayout.snapshotData.designList = await initializeDesignList( + this, + snapshotLayout + ); return snapshotLayout; }, - getContextMenu: async function (obj, menu) { + async getContextMenu (obj, menu) { const app = qlik.currApp(this); const isPersonalResult = await app.global.isPersonalMode(); - if (!this.$scope.layout.allowexportxls || (isPersonalResult && isPersonalResult.qReturn)) { + if ( + !this.$scope.layout.allowexportxls || + (isPersonalResult && isPersonalResult.qReturn) + ) { return menu; } menu.addItem({ - translation: "Export as XLS", - tid: "export-excel", - icon: "export", + translation: 'Export as XLS', + tid: 'export-excel', + icon: 'export', select: () => { exportXLS( this.$element, this.$scope.layout.title, this.$scope.layout.subtitle, - this.$scope.layout.footnote); + this.$scope.layout.footnote + ); } }); return menu; diff --git a/src/initialize-transformed.js b/src/initialize-transformed.js index f2b1b95..d4f77da 100644 --- a/src/initialize-transformed.js +++ b/src/initialize-transformed.js @@ -71,56 +71,56 @@ function generateMatrixCell ({ cell, dimension1Information, dimension2Informatio return matrixCell; } -let lastRow = 0; -function generateDataSet ( - component, dimensionsInformation, measurementsInformation, dataCube) { +function generateDataSet (component, dimensionsInformation, measurementsInformation, dataCube) { const measurements = generateMeasurements(measurementsInformation); let dimension1 = []; let dimension2 = []; let matrix = []; const hasSecondDimension = dimensionsInformation.length > 1; - dataCube.forEach(row => { - lastRow += 1; - const dimension1Entry = generateDimensionEntry(dimensionsInformation[0], row[0]); - dimension1.push(dimension1Entry); - let dimension2Entry; - let firstDataCell = 1; - if (hasSecondDimension) { - dimension2Entry = generateDimensionEntry(dimensionsInformation[1], row[1]); - dimension2.push(dimension2Entry); - firstDataCell = 2; - } - let matrixRow = row - .slice(firstDataCell, row.length) - .map((cell, cellIndex) => { - const measurementInformation = measurements[cellIndex]; - measurementInformation.index = cellIndex; - const dimension1Information = row[0]; // eslint-disable-line prefer-destructuring - const dimension2Information = hasSecondDimension ? row[1] : null; - const generatedCell = generateMatrixCell({ - cell, - dimension1Information, - dimension2Information, - measurementInformation + // eslint-disable-next-line no-undefined + for (let index = 0; dataCube[index] !== undefined; index++) { + // eslint-disable-next-line no-loop-func + dataCube[index].forEach(row => { + const dimension1Entry = generateDimensionEntry(dimensionsInformation[0], row[0]); + dimension1.push(dimension1Entry); + let dimension2Entry; + let firstDataCell = 1; + if (hasSecondDimension) { + dimension2Entry = generateDimensionEntry(dimensionsInformation[1], row[1]); + dimension2.push(dimension2Entry); + firstDataCell = 2; + } + let matrixRow = row + .slice(firstDataCell, row.length) + .map((cell, cellIndex) => { + const measurementInformation = measurements[cellIndex]; + measurementInformation.index = cellIndex; + const dimension1Information = row[0]; // eslint-disable-line prefer-destructuring + const dimension2Information = hasSecondDimension ? row[1] : null; + const generatedCell = generateMatrixCell({ + cell, + dimension1Information, + dimension2Information, + measurementInformation + }); + return generatedCell; }); - return generatedCell; - }); - - let appendToRowIndex = matrix.length; - if (hasSecondDimension) { + let appendToRowIndex = matrix.length; + if (hasSecondDimension) { // See if there already is a row for the current dim1 - for (let i = 0; i < matrix.length; i++) { - if (matrix[i][0].parents.dimension1.header === matrixRow[0].parents.dimension1.header) { - appendToRowIndex = i; - matrixRow = matrix[i].concat(matrixRow); + for (let i = 0; i < matrix.length; i++) { + if (matrix[i][0].parents.dimension1.header === matrixRow[0].parents.dimension1.header) { + appendToRowIndex = i; + matrixRow = matrix[i].concat(matrixRow); + } } } - } - matrix[appendToRowIndex] = matrixRow; - }); + matrix[appendToRowIndex] = matrixRow; + }); + } // filter header dimensions to only have distinct values dimension1 = distinctArray(dimension1); @@ -194,12 +194,10 @@ function appendMissingCells ( return index; } -function initializeTransformed ({ $element, component, dataCube, designList, layout }) { +function initializeTransformed ({ component, dataCube, designList, layout }) { const dimensionsInformation = component.backendApi.getDimensionInfos(); const measurementsInformation = component.backendApi.getMeasureInfos(); const dimensionCount = layout.qHyperCube.qDimensionInfo.length; - const rowCount = component.backendApi.getRowCount(); - const maxLoops = layout.maxloops; const { dimension1, dimension2, @@ -259,7 +257,6 @@ function initializeTransformed ({ $element, component, dataCube, designList, lay cellWidth: cellWidth, errorMessage: layout.errormessage, footnote: layout.footnote, - maxLoops, subtitle: layout.subtitle, title: layout.title, useColumnSeparator: layout.separatorcols && dimensionCount > 1 @@ -320,20 +317,6 @@ function initializeTransformed ({ $element, component, dataCube, designList, lay } }; - if (rowCount > lastRow && rowCount <= (maxLoops * 1000)) { - const requestPage = [ - { - qHeight: Math.min(1000, rowCount - lastRow), - qLeft: 0, - qTop: matrix.length, - qWidth: 10 // should be # of columns - } - ]; - component.backendApi.getData(requestPage).then(() => { - component.paint($element, layout); - }); - } - return transformedProperties; } diff --git a/src/main.less b/src/main.less index 384a250..30e2e1d 100644 --- a/src/main.less +++ b/src/main.less @@ -105,6 +105,20 @@ width: 100%; } + .error { + position: absolute; /*Define position */ + width: 100%; /* Full width (cover the whole page) */ + height: 100%; /* Full height (cover the whole page) */ + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 1000; /* Specify a stack order in case you're using a different order for other elements */ + display: flex; + justify-content: center; + align-items: center; + } + .kpi-table .fdim-cells, .data-table td { line-height: 1em !important; diff --git a/src/root.jsx b/src/root.jsx index b66be8f..e4dfbbf 100644 --- a/src/root.jsx +++ b/src/root.jsx @@ -1,8 +1,8 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import HeadersTable from './headers-table/index.jsx'; -import DataTable from './data-table/index.jsx'; -import { LinkedScrollWrapper, LinkedScrollSection } from './linked-scroll'; +import React from "react"; +import PropTypes from "prop-types"; +import HeadersTable from "./headers-table/index.jsx"; +import DataTable from "./data-table/index.jsx"; +import { LinkedScrollWrapper, LinkedScrollSection } from "./linked-scroll"; class Root extends React.PureComponent { constructor (props) { @@ -25,7 +25,7 @@ class Root extends React.PureComponent { render () { const { editmodeClass, component, state } = this.props; - const { data, general, styling } = state; + const { data, general, styling, error } = state; // Determine cell- and column separator width let cellWidth = '0px'; @@ -48,72 +48,80 @@ class Root extends React.PureComponent { let separatorWidth = 0; if (general.useColumnSeparator) { separatorCount = data.headers.dimension2.length - 1; - separatorWidth = Math.min(Math.floor(tableWidth * 0.2 / separatorCount), 8); + separatorWidth = Math.min( + Math.floor((tableWidth * 0.2) / separatorCount), + 8 + ); columnSeparatorWidth = `${separatorWidth}px`; } - const separatorWidthSum = (separatorWidth + borderWidth) * separatorCount; - cellWidth = `${Math.floor((tableWidth - separatorWidthSum - headerMarginRight - borderWidth) - / rowCellCount) - borderWidth}px`; + const separatorWidthSum = + (separatorWidth + borderWidth) * separatorCount; + cellWidth = `${Math.floor( + (tableWidth - separatorWidthSum - headerMarginRight - borderWidth) / + rowCellCount) - borderWidth}px`; } } return (
- -
- - - - + {error ? ( +
+ {state.layout.errormessage}
-
- + ) : ( + +
- - + + +
+
- - -
-
+ + + + + + +
+ + )}
); } @@ -123,9 +131,9 @@ Root.propTypes = { component: PropTypes.shape({}).isRequired, editmodeClass: PropTypes.string.isRequired, state: PropTypes.shape({ - data: PropTypes.object.isRequired, - general: PropTypes.object.isRequired, - styling: PropTypes.object.isRequired + data: PropTypes.object, + general: PropTypes.object, + styling: PropTypes.object }).isRequired };