Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d3c39bea75 | ||
|
|
433a725f33 | ||
|
|
769d5cfa3f | ||
|
|
9d925b6205 | ||
|
|
34527c3d6d | ||
|
|
35d489c2e2 | ||
|
|
9ef9981305 | ||
|
|
398192e057 | ||
|
|
4421217cb0 | ||
|
|
c92be00ca7 | ||
|
|
c66dfdc06c | ||
|
|
a882b1d6aa | ||
|
|
554b029569 | ||
|
|
4a15628325 | ||
|
|
fdb2aaaef4 | ||
|
|
a400e9c233 | ||
|
|
091c564a75 | ||
|
|
99eba8afcb | ||
|
|
cb78a2f2f9 | ||
|
|
f255efbf5d | ||
|
|
2f2d08fedd | ||
|
|
ac8b70bc84 | ||
|
|
85228412cc | ||
|
|
03dfc0ce93 | ||
|
|
48427df559 | ||
|
|
7fda7aa2d9 | ||
|
|
4ba12b8b2d | ||
|
|
07af7b509e |
Binary file not shown.
|
Before Width: | Height: | Size: 123 B After Width: | Height: | Size: 7.5 KiB |
@@ -1,44 +0,0 @@
|
||||
Accounts;Bold;Background;FontStyle;LetterColor;Align;Size;Comment
|
||||
Revenues;;rgb(183, 219, 255);<italic>;;<center>;;<comment>
|
||||
Gross sales revenues;;;;;;;
|
||||
Less return & allowances;;;;;;;
|
||||
Net sales revenues;<bold>;#efefef;;;;;
|
||||
Cost of goods sold;<bold>;;;;;;
|
||||
Direct materials;;;;;;;
|
||||
Direct labor;;;;;;;
|
||||
Manufacturing overhead;;#b7dbff;<italic>;;<center>;;<comment>
|
||||
Indirect labor;;;;;;;
|
||||
Depreciation, manufacturing equip;;;;;;;
|
||||
Other mfr overhead;;;;;;;
|
||||
Net mfr overhead;<bold>;#CCC0FF;;;;;
|
||||
Net costs of goods sold;<bold>;#CCC0FF;;;;;
|
||||
Gross profit;<bold>;#C4C4C4;;;<center>;<large>;
|
||||
Operating expenses;<bold>;;<italic>;;;;
|
||||
Selling expenses;;;;;;;
|
||||
Sales salaries;;;;;;;
|
||||
Warranty expenses;;;;;;;
|
||||
Depreciation, store equipment;;;;;;;
|
||||
Other selling expenses3;;;;;;;
|
||||
Total selling expenses;<bold>;#CCC0FF;;;;;
|
||||
General & administrative expenses;;#b7dbff;<italic>;;<center>;;<comment>
|
||||
Administration salaries;;;;;;;
|
||||
Rent expenses;;;;;;;
|
||||
Depreciation, computers;;;;;;;
|
||||
Other general & admin expenses;;;;;;;
|
||||
total general & admin expenses;<bold>;#efefef;;;;;
|
||||
total operating expenses;<bold>;#CCC0FF;;;;;
|
||||
Operating income before taxes;<bold>;#C4C4C4;;<white>;;<large>;
|
||||
Financial revenue & expenses;;#b7dbff;<italic>;;<center>;;<comment>
|
||||
Revenue from investments;;;;;;;
|
||||
Less interest expenses;;;;;;;
|
||||
Net financial gain (expense);;;;;;;
|
||||
Income before tax & extraordinary items;<bold>;#C4C4C4;;<white>;;<large>;
|
||||
Less income tax on operations;;;;;;;
|
||||
Income before extraordinary items;;;;;;;
|
||||
Extraordinary items;;#b7dbff;<italic>;;<center>;;<comment>
|
||||
Sale of land;;;;;;;
|
||||
Less initial cost;;;;;;;
|
||||
Net gain on sale of land;<bold>;#efefef;;;;;
|
||||
Less income tax on gain;;;;;;;
|
||||
Extraordinary items after tax;<bold>;#efefef;;;;;
|
||||
Net Income (Profit);<bold>;#C4C4C4;;<white>;<center>;<large>;
|
||||
|
@@ -1,21 +0,0 @@
|
||||
Accounts;Bold;Background;FontStyle;LetterColor;Align;Size;Comment
|
||||
Revenues;<bold>;;<italic>;;<center>;;<comment>
|
||||
Net sales revenues;<bold>;rgb(128, 191, 255);;;;;
|
||||
Cost of goods sold;<bold>;rgb(128, 191, 255);;;;;
|
||||
Manufacturing overhead;<bold>;;<italic>;;<center>;;<comment>
|
||||
Net mfr overhead;<bold>;rgb(128, 191, 255);;;;;
|
||||
Net costs of goods sold;<bold>;rgb(128, 191, 255);;;;;
|
||||
Gross profit;<bold>;rgb(0, 102, 204);<white>;;<center>;<large>;
|
||||
Operating expenses;<bold>;;<italic>;;;;
|
||||
Total selling expenses;<bold>;rgb(128, 191, 255);;;;;
|
||||
General & administrative expenses;<bold>;;<italic>;;<center>;;<comment>
|
||||
Other general & admin expenses;<bold>;rgb(128, 191, 255);<white>;;<center>;<large>;
|
||||
total general & admin expenses;<bold>;#efefef;;;;;
|
||||
total operating expenses;<bold>;rgb(128, 191, 255);;;;;
|
||||
Operating income before taxes;<bold>;rgb(0, 102, 204);;<white>;;<large>;
|
||||
Financial revenue & expenses;<bold>;;<italic>;;<center>;;<comment>
|
||||
Income before tax & extraordinary items;<bold>;rgb(0, 102, 204);;<white>;;<large>;
|
||||
Extraordinary items;<bold>;;<italic>;;<center>;;<comment>
|
||||
Net gain on sale of land;<bold>;rgb(0, 102, 204);<white>;;<center>;<large>;
|
||||
Extraordinary items after tax;<bold>;rgb(0, 102, 204);<white>;;<center>;<large>;
|
||||
Net Income (Profit);<bold>;#191970;;<white>;<center>;<large>;
|
||||
|
Binary file not shown.
@@ -1,21 +0,0 @@
|
||||
Accounts;Bold;Background;FontStyle;LetterColor;Align;Size;Comment
|
||||
Revenues;<bold>;;<italic>;;<center>;;<comment>
|
||||
Net sales revenues;<bold>;RGB(225,226,226);;;;;
|
||||
Cost of goods sold;<bold>;RGB(225,226,226);;;;;
|
||||
Manufacturing overhead;<bold>;;<italic>;;<center>;;<comment>
|
||||
Net mfr overhead;<bold>;RGB(225,226,226);;;;;
|
||||
Net costs of goods sold;<bold>;RGB(225,226,226);;;;;
|
||||
Gross profit;<bold>;RGB(193,216,47);;;<center>;<large>;
|
||||
Operating expenses;<bold>;;<italic>;;;;
|
||||
Total selling expenses;<bold>;RGB(225,226,226);;;;;
|
||||
General & administrative expenses;<bold>;;<italic>;;<center>;;<comment>
|
||||
Other general & admin expenses;<bold>;rgb(128, 191, 255);<white>;;<center>;<large>;
|
||||
total general & admin expenses;<bold>;#efefef;;;;;
|
||||
total operating expenses;<bold>;rgb(128, 191, 255);<white>;;;;
|
||||
Operating income before taxes;<bold>;RGB(193,216,47);;;;<large>;
|
||||
Financial revenue & expenses;<bold>;;<italic>;;<center>;;<comment>
|
||||
Income before tax & extraordinary items;<bold>;RGB(193,216,47);;;;<large>;
|
||||
Extraordinary items;<bold>;;<italic>;;<center>;;<comment>
|
||||
Net gain on sale of land;<bold>;RGB(193,216,47);;;<center>;<large>;
|
||||
Extraordinary items after tax;<bold>;RGB(193,216,47);;;<center>;<large>;
|
||||
Net Income (Profit);<bold>;#191970;;<white>;<center>;<large>;
|
||||
|
@@ -108,7 +108,12 @@ DataCell.propTypes = {
|
||||
}).isRequired,
|
||||
qlik: PropTypes.shape({
|
||||
backendApi: PropTypes.shape({
|
||||
selectValues: PropTypes.func.isRequired
|
||||
selectValues: function (props, propName) {
|
||||
if (props.isSnapshot || typeof props[propName] === 'function') {
|
||||
return null;
|
||||
}
|
||||
return new Error('Missing implementation of qlik.backendApi.selectValues.');
|
||||
}
|
||||
}).isRequired
|
||||
}).isRequired,
|
||||
styleBuilder: PropTypes.shape({
|
||||
|
||||
@@ -4,7 +4,8 @@ import PropTypes from 'prop-types';
|
||||
const HeaderPadding = ({ styleBuilder, styling }) => {
|
||||
if (styling.usePadding && !styleBuilder.hasCustomFileStyle()) {
|
||||
const paddingStyle = {
|
||||
fontFamily: styling.options.fontFamily
|
||||
fontFamily: styling.options.fontFamily,
|
||||
marginLeft: '15px'
|
||||
};
|
||||
return (
|
||||
<span style={paddingStyle} />
|
||||
|
||||
@@ -25,14 +25,14 @@ class RowHeader extends React.PureComponent {
|
||||
onClick={this.handleSelect}
|
||||
style={rowStyle}
|
||||
>
|
||||
<HeaderPadding
|
||||
styleBuilder={styleBuilder}
|
||||
styling={styling}
|
||||
/>
|
||||
<Tooltip
|
||||
isTooltipActive={!inEditState}
|
||||
tooltipText={entry.displayValue}
|
||||
>
|
||||
<HeaderPadding
|
||||
styleBuilder={styleBuilder}
|
||||
styling={styling}
|
||||
/>
|
||||
{entry.displayValue}
|
||||
</Tooltip>
|
||||
</td>
|
||||
@@ -46,7 +46,12 @@ RowHeader.propTypes = {
|
||||
}).isRequired,
|
||||
qlik: PropTypes.shape({
|
||||
backendApi: PropTypes.shape({
|
||||
selectValues: PropTypes.func.isRequired
|
||||
selectValues: function (props, propName) {
|
||||
if (props.isSnapshot || typeof props[propName] === 'function') {
|
||||
return null;
|
||||
}
|
||||
return new Error('Missing implementation of qlik.backendApi.selectValues.');
|
||||
}
|
||||
}).isRequired
|
||||
}).isRequired,
|
||||
rowStyle: PropTypes.shape({}).isRequired,
|
||||
|
||||
91
src/dataset.js
Normal file
91
src/dataset.js
Normal file
@@ -0,0 +1,91 @@
|
||||
import qlik from 'qlik';
|
||||
|
||||
function createCube (definition, app) {
|
||||
return new Promise(resolve => {
|
||||
app.createCube(definition, resolve);
|
||||
});
|
||||
}
|
||||
|
||||
async function buildDataCube (originCubeDefinition, dimensionIndexes, app) {
|
||||
const cubeDefinition = {
|
||||
...originCubeDefinition,
|
||||
qInitialDataFetch: [
|
||||
{
|
||||
qHeight: 1000,
|
||||
qWidth: 10
|
||||
}
|
||||
],
|
||||
qDimensions: [originCubeDefinition.qDimensions[dimensionIndexes.dimension1]],
|
||||
qMeasures: originCubeDefinition.qMeasures
|
||||
};
|
||||
if (dimensionIndexes.dimension2) {
|
||||
cubeDefinition.qDimensions.push(originCubeDefinition.qDimensions[dimensionIndexes.dimension2]);
|
||||
}
|
||||
const cube = await createCube(cubeDefinition, app);
|
||||
|
||||
return cube.qHyperCube.qDataPages[0].qMatrix;
|
||||
}
|
||||
|
||||
async function buildDesignCube (originCubeDefinition, dimensionIndexes, app) {
|
||||
if (!dimensionIndexes.design) {
|
||||
return null;
|
||||
}
|
||||
const cube = await createCube({
|
||||
qInitialDataFetch: [
|
||||
{
|
||||
qHeight: 1000,
|
||||
qWidth: 1
|
||||
}
|
||||
],
|
||||
qDimensions: [originCubeDefinition.qDimensions[dimensionIndexes.design]]
|
||||
}, app);
|
||||
|
||||
return cube.qHyperCube.qDataPages[0].qMatrix;
|
||||
}
|
||||
|
||||
const STYLE_SEPARATOR_COUNT = 7;
|
||||
function findDesignDimension (qMatrix) {
|
||||
return qMatrix[0].map(entry => (entry.qText.match(/;/g) || []).length).indexOf(STYLE_SEPARATOR_COUNT);
|
||||
}
|
||||
|
||||
function getDimensionIndexes (dimensionsInformation, designDimensionIndex) {
|
||||
const hasDesign = designDimensionIndex !== -1;
|
||||
const nonDesignDimensionCount = hasDesign ? dimensionsInformation.length - 1 : dimensionsInformation.length;
|
||||
const dimension1 = designDimensionIndex === 0 ? 1 : 0;
|
||||
let dimension2 = false;
|
||||
if (nonDesignDimensionCount === 2) {
|
||||
dimension2 = hasDesign && designDimensionIndex < 2 ? 2 : 1;
|
||||
}
|
||||
const design = hasDesign && designDimensionIndex;
|
||||
const firstMeasurementIndex = dimensionsInformation.length;
|
||||
return {
|
||||
design,
|
||||
dimension1,
|
||||
dimension2,
|
||||
firstMeasurementIndex
|
||||
};
|
||||
}
|
||||
|
||||
export async function initializeCubes ({ component, layout }) {
|
||||
const app = qlik.currApp(component);
|
||||
const designDimensionIndex = findDesignDimension(layout.qHyperCube.qDataPages[0].qMatrix);
|
||||
const dimensionsInformation = layout.qHyperCube.qDimensionInfo;
|
||||
const dimensionIndexes = getDimensionIndexes(dimensionsInformation, designDimensionIndex);
|
||||
|
||||
let properties;
|
||||
if (component.backendApi.isSnapshot) {
|
||||
// Fetch properties of source
|
||||
properties = (await app.getObjectProperties(layout.sourceObjectId)).properties;
|
||||
} else {
|
||||
properties = await component.backendApi.getProperties();
|
||||
}
|
||||
|
||||
const originCubeDefinition = properties.qHyperCubeDef;
|
||||
const designCube = await buildDesignCube(originCubeDefinition, dimensionIndexes, app);
|
||||
const dataCube = await buildDataCube(originCubeDefinition, dimensionIndexes, app);
|
||||
|
||||
return {
|
||||
design: designCube,
|
||||
data: dataCube
|
||||
};
|
||||
}
|
||||
@@ -27,23 +27,23 @@ const header = {
|
||||
component: 'color-picker',
|
||||
defaultValue: {
|
||||
index: 6,
|
||||
color: "#4477aa"
|
||||
color: '#4477aa'
|
||||
},
|
||||
dualOutput: true,
|
||||
label: 'BackGround Header Color',
|
||||
label: 'Background Header Color',
|
||||
ref: 'HeaderColorSchema',
|
||||
type: 'object'
|
||||
type: 'object',
|
||||
dualOutput: true
|
||||
},
|
||||
HeaderTextColor: {
|
||||
ref: 'HeaderTextColorSchema',
|
||||
label: 'Text Header Color',
|
||||
component: 'color-picker',
|
||||
dualOutput: true,
|
||||
defaultValue: {
|
||||
index: 1,
|
||||
color: "#ffffff"
|
||||
color: '#ffffff'
|
||||
},
|
||||
type: 'object'
|
||||
type: 'object',
|
||||
dualOutput: true
|
||||
},
|
||||
HeaderFontSize: {
|
||||
ref: 'lettersizeheader',
|
||||
@@ -60,7 +60,7 @@ const header = {
|
||||
label: 'Medium'
|
||||
}
|
||||
],
|
||||
defaultValue: 2
|
||||
defaultValue: 1
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import pagination from './pagination';
|
||||
import header from './header';
|
||||
import formatted from './formatted';
|
||||
import tableFormat from './table-format';
|
||||
import conceptSemaphores from './concept-semaphores';
|
||||
import metricSemaphores from './metric-semaphores';
|
||||
|
||||
@@ -21,7 +21,7 @@ const definition = {
|
||||
settings: {
|
||||
items: {
|
||||
ConceptSemaphores: conceptSemaphores,
|
||||
Formatted: formatted,
|
||||
Formatted: tableFormat,
|
||||
Header: header,
|
||||
MetricSemaphores: metricSemaphores,
|
||||
Pagination: pagination
|
||||
|
||||
@@ -23,7 +23,7 @@ const metricSemaphores = {
|
||||
ref: 'metricssemaphore',
|
||||
translation: 'Metrics affected (1,2,4,...)',
|
||||
type: 'string',
|
||||
defaultValue: '0',
|
||||
defaultValue: '-',
|
||||
show (data) {
|
||||
return !data.allmetrics;
|
||||
}
|
||||
@@ -39,6 +39,7 @@ const metricSemaphores = {
|
||||
label: 'Critic Color Fill',
|
||||
type: 'object',
|
||||
component: 'color-picker',
|
||||
dualOutput: true,
|
||||
defaultValue: {
|
||||
index: 8,
|
||||
color: '#f93f17'
|
||||
@@ -49,6 +50,7 @@ const metricSemaphores = {
|
||||
label: 'Critic Color Text',
|
||||
type: 'object',
|
||||
component: 'color-picker',
|
||||
dualOutput: true,
|
||||
defaultValue: {
|
||||
index: 11,
|
||||
color: '#ffffff'
|
||||
@@ -65,6 +67,7 @@ const metricSemaphores = {
|
||||
label: 'Medium Color Fill',
|
||||
type: 'object',
|
||||
component: 'color-picker',
|
||||
dualOutput: true,
|
||||
defaultValue: {
|
||||
index: 9,
|
||||
color: '#ffcf02'
|
||||
@@ -75,6 +78,7 @@ const metricSemaphores = {
|
||||
label: 'Medium Color Text',
|
||||
type: 'object',
|
||||
component: 'color-picker',
|
||||
dualOutput: true,
|
||||
defaultValue: {
|
||||
index: 12,
|
||||
color: '#000000'
|
||||
@@ -85,6 +89,7 @@ const metricSemaphores = {
|
||||
label: 'Success Color Fill',
|
||||
type: 'object',
|
||||
component: 'color-picker',
|
||||
dualOutput: true,
|
||||
defaultValue: {
|
||||
index: 10,
|
||||
color: '#276e27'
|
||||
@@ -95,6 +100,7 @@ const metricSemaphores = {
|
||||
label: 'Success Color Text',
|
||||
type: 'object',
|
||||
component: 'color-picker',
|
||||
dualOutput: true,
|
||||
defaultValue: {
|
||||
index: 11,
|
||||
color: '#ffffff'
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
const formatted = {
|
||||
// fixes case for when there are 3 dimensions, missies the case with 1 design dimension and 1 data dimension
|
||||
function hasDesignDimension (data) {
|
||||
return data.qHyperCubeDef.qDimensions.length > 2;
|
||||
}
|
||||
|
||||
const tableFormat = {
|
||||
type: 'items',
|
||||
label: 'Table Format',
|
||||
items: {
|
||||
@@ -6,7 +11,8 @@ const formatted = {
|
||||
ref: 'indentbool',
|
||||
type: 'boolean',
|
||||
label: 'Indent',
|
||||
defaultValue: true
|
||||
defaultValue: false,
|
||||
show: data => !hasDesignDimension(data)
|
||||
},
|
||||
SeparatorColumns: {
|
||||
ref: 'separatorcols',
|
||||
@@ -14,31 +20,17 @@ const formatted = {
|
||||
label: 'Separator Columns',
|
||||
defaultValue: false
|
||||
},
|
||||
CustomFileBool: {
|
||||
ref: 'customfilebool',
|
||||
type: 'boolean',
|
||||
label: 'Include External File',
|
||||
defaultValue: false
|
||||
},
|
||||
CustomFile: {
|
||||
ref: 'customfile',
|
||||
label: 'Name of CSV file (; separated)',
|
||||
type: 'string',
|
||||
defaultValue: '',
|
||||
show (data) {
|
||||
return data.customfilebool;
|
||||
}
|
||||
},
|
||||
rowEvenBGColor: {
|
||||
component: 'color-picker',
|
||||
defaultValue: {
|
||||
color: '#fff',
|
||||
index: 1
|
||||
},
|
||||
dualOutput: true,
|
||||
label: 'Even row background color',
|
||||
ref: 'rowEvenBGColor',
|
||||
type: 'object'
|
||||
type: 'object',
|
||||
dualOutput: true,
|
||||
show: data => !hasDesignDimension(data)
|
||||
},
|
||||
rowOddBGColor: {
|
||||
component: 'color-picker',
|
||||
@@ -46,10 +38,11 @@ const formatted = {
|
||||
color: '#b6d7ea',
|
||||
index: 4
|
||||
},
|
||||
dualOutput: true,
|
||||
label: 'Odd row background color',
|
||||
ref: 'rowOddBGColor',
|
||||
type: 'object'
|
||||
type: 'object',
|
||||
dualOutput: true,
|
||||
show: data => !hasDesignDimension(data)
|
||||
},
|
||||
BodyTextColor: {
|
||||
ref: 'BodyTextColorSchema',
|
||||
@@ -99,9 +92,7 @@ const formatted = {
|
||||
}
|
||||
],
|
||||
defaultValue: 'Black',
|
||||
show (data) {
|
||||
return !data.customfilebool;
|
||||
}
|
||||
show: data => !hasDesignDimension(data)
|
||||
},
|
||||
FontFamily: {
|
||||
ref: 'FontFamily',
|
||||
@@ -110,35 +101,35 @@ const formatted = {
|
||||
label: 'FontFamily',
|
||||
options: [
|
||||
{
|
||||
value: 'QlikView Sans',
|
||||
value: 'QlikView Sans, -apple-system, sans-serif',
|
||||
label: 'QlikView Sans'
|
||||
},
|
||||
{
|
||||
value: 'Arial',
|
||||
value: 'Arial, -apple-system, sans-serif',
|
||||
label: 'Arial'
|
||||
},
|
||||
{
|
||||
value: 'Calibri',
|
||||
value: 'Calibri, -apple-system, sans-serif',
|
||||
label: 'Calibri'
|
||||
},
|
||||
{
|
||||
value: 'Comic Sans MS',
|
||||
value: 'Comic Sans MS, -apple-system, sans-serif',
|
||||
label: 'Comic Sans MS'
|
||||
},
|
||||
{
|
||||
value: 'MS Sans Serif',
|
||||
value: 'MS Sans Serif, -apple-system, sans-serif',
|
||||
label: 'MS Sans Serif'
|
||||
},
|
||||
{
|
||||
value: 'Tahoma',
|
||||
value: 'Tahoma, -apple-system, sans-serif',
|
||||
label: 'Tahoma'
|
||||
},
|
||||
{
|
||||
value: 'Verdana',
|
||||
value: 'Verdana, -apple-system, sans-serif',
|
||||
label: 'Verdana'
|
||||
}
|
||||
],
|
||||
defaultValue: 'QlikView Sans'
|
||||
defaultValue: 'QlikView Sans, -apple-system, sans-serif'
|
||||
},
|
||||
DataFontSize: {
|
||||
ref: 'lettersize',
|
||||
@@ -230,4 +221,4 @@ const formatted = {
|
||||
}
|
||||
};
|
||||
|
||||
export default formatted;
|
||||
export default tableFormat;
|
||||
@@ -19,7 +19,7 @@ class ColumnHeader extends React.PureComponent {
|
||||
|
||||
const style = {
|
||||
...baseCSS,
|
||||
fontSize: `${14 + styling.headerOptions.fontSizeAdjustment} px`,
|
||||
fontSize: `${14 + styling.headerOptions.fontSizeAdjustment}px`,
|
||||
height: '45px',
|
||||
verticalAlign: 'middle'
|
||||
};
|
||||
@@ -57,7 +57,12 @@ ColumnHeader.propTypes = {
|
||||
}).isRequired,
|
||||
qlik: PropTypes.shape({
|
||||
backendApi: PropTypes.shape({
|
||||
selectValues: PropTypes.func.isRequired
|
||||
selectValues: function (props, propName) {
|
||||
if (props.isSnapshot || typeof props[propName] === 'function') {
|
||||
return null;
|
||||
}
|
||||
return new Error('Missing implementation of qlik.backendApi.selectValues.');
|
||||
}
|
||||
}).isRequired
|
||||
}).isRequired,
|
||||
styling: PropTypes.shape({
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ExportButton from '../export-button.jsx';
|
||||
import { HEADER_FONT_SIZE } from '../initialize-transformed';
|
||||
|
||||
const ExportColumnHeader = ({ baseCSS, general, title, allowExcelExport, hasSecondDimension, styling }) => {
|
||||
const rowSpan = hasSecondDimension ? 2 : 1;
|
||||
const isMediumFontSize = styling.headerOptions.fontSizeAdjustment === HEADER_FONT_SIZE.MEDIUM;
|
||||
const style = {
|
||||
...baseCSS,
|
||||
cursor: 'default',
|
||||
fontSize: `${16 + styling.headerOptions.fontSizeAdjustment} px`,
|
||||
height: '80px',
|
||||
fontSize: `${16 + styling.headerOptions.fontSizeAdjustment}px`,
|
||||
height: isMediumFontSize ? '100px' : '80px',
|
||||
verticalAlign: 'middle',
|
||||
width: '230px'
|
||||
};
|
||||
|
||||
@@ -126,7 +126,12 @@ HeadersTable.propTypes = {
|
||||
general: PropTypes.shape({}).isRequired,
|
||||
qlik: PropTypes.shape({
|
||||
backendApi: PropTypes.shape({
|
||||
selectValues: PropTypes.func.isRequired
|
||||
selectValues: function (props, propName) {
|
||||
if (props.isSnapshot || typeof props[propName] === 'function') {
|
||||
return null;
|
||||
}
|
||||
return new Error('Missing implementation of qlik.backendApi.selectValues.');
|
||||
}
|
||||
}).isRequired
|
||||
}).isRequired,
|
||||
styling: PropTypes.shape({
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { HEADER_FONT_SIZE } from '../initialize-transformed';
|
||||
import Tooltip from '../tooltip/index.jsx';
|
||||
|
||||
const MeasurementColumnHeader = ({ baseCSS, general, hasSecondDimension, measurement, styling }) => {
|
||||
const title = `${measurement.name} ${measurement.magnitudeLabelSuffix}`;
|
||||
const { fontSizeAdjustment } = styling.headerOptions;
|
||||
const isMediumFontSize = styling.headerOptions.fontSizeAdjustment === HEADER_FONT_SIZE.MEDIUM;
|
||||
|
||||
if (hasSecondDimension) {
|
||||
const isPercentageFormat = measurement.format.substring(measurement.format.length - 1) === '%';
|
||||
let baseFontSize = 14;
|
||||
@@ -15,8 +19,8 @@ const MeasurementColumnHeader = ({ baseCSS, general, hasSecondDimension, measure
|
||||
const cellStyle = {
|
||||
...baseCSS,
|
||||
cursor: 'default',
|
||||
fontSize: `${baseFontSize + fontSizeAdjustment} px`,
|
||||
height: '25px',
|
||||
fontSize: `${baseFontSize + fontSizeAdjustment}px`,
|
||||
height: isMediumFontSize ? '50px' : '25px',
|
||||
verticalAlign: 'middle'
|
||||
};
|
||||
return (
|
||||
@@ -25,18 +29,23 @@ const MeasurementColumnHeader = ({ baseCSS, general, hasSecondDimension, measure
|
||||
style={cellStyle}
|
||||
>
|
||||
<span className="wrapclass25">
|
||||
{title}
|
||||
<Tooltip
|
||||
tooltipText={title}
|
||||
>
|
||||
{title}
|
||||
</Tooltip>
|
||||
</span>
|
||||
</th>
|
||||
);
|
||||
}
|
||||
|
||||
const isLong = (title.length > 11 && fontSizeAdjustment === 0) || (title.length > 12 && fontSizeAdjustment === -2);
|
||||
const suffixWrap = isLong ? '70' : 'empty';
|
||||
const style = {
|
||||
...baseCSS,
|
||||
cursor: 'default',
|
||||
fontSize: `${15 + fontSizeAdjustment} px`,
|
||||
height: '80px',
|
||||
fontSize: `${15 + fontSizeAdjustment}px`,
|
||||
height: isMediumFontSize ? '100px' : '80px',
|
||||
verticalAlign: 'middle'
|
||||
};
|
||||
return (
|
||||
|
||||
15
src/index.js
15
src/index.js
@@ -10,27 +10,34 @@ export default {
|
||||
controller: [
|
||||
'$scope',
|
||||
'$timeout',
|
||||
function () { }
|
||||
function controller () {}
|
||||
],
|
||||
design: {
|
||||
dimensions: {
|
||||
max: 1,
|
||||
min: 0
|
||||
}
|
||||
},
|
||||
data: {
|
||||
dimensions: {
|
||||
max: 2,
|
||||
max: 3,
|
||||
min: 1,
|
||||
uses: 'dimensions'
|
||||
},
|
||||
measures: {
|
||||
max: 9,
|
||||
max: 8,
|
||||
min: 1,
|
||||
uses: 'measures'
|
||||
}
|
||||
},
|
||||
definition,
|
||||
initialProperties: {
|
||||
version: 1.0,
|
||||
qHyperCubeDef: {
|
||||
qDimensions: [],
|
||||
qInitialDataFetch: [
|
||||
{
|
||||
qHeight: 1000,
|
||||
qHeight: 1,
|
||||
qWidth: 10
|
||||
}
|
||||
],
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import jQuery from 'jquery';
|
||||
import { distinctArray } from './utilities';
|
||||
|
||||
export const HEADER_FONT_SIZE = {
|
||||
SMALL: -1,
|
||||
MEDIUM: 1
|
||||
};
|
||||
|
||||
function getAlignment (option) {
|
||||
const alignmentOptions = {
|
||||
1: 'left',
|
||||
@@ -13,8 +17,8 @@ function getAlignment (option) {
|
||||
|
||||
function getFontSizeAdjustment (option) {
|
||||
const fontSizeAdjustmentOptions = {
|
||||
1: -1,
|
||||
2: 1,
|
||||
1: HEADER_FONT_SIZE.SMALL,
|
||||
2: HEADER_FONT_SIZE.MEDIUM,
|
||||
3: 2
|
||||
};
|
||||
|
||||
@@ -103,15 +107,16 @@ function generateMatrixCell ({ cell, dimension1Information, dimension2Informatio
|
||||
}
|
||||
|
||||
let lastRow = 0;
|
||||
function generateDataSet (component, dimensionsInformation, measurementsInformation) {
|
||||
function generateDataSet (component, dimensionsInformation, measurementsInformation, cubes) {
|
||||
const dimension1 = [];
|
||||
const dimension2 = [];
|
||||
const measurements = generateMeasurements(measurementsInformation);
|
||||
let matrix = [];
|
||||
|
||||
let previousDim1Entry;
|
||||
const hasSecondDimension = dimensionsInformation.length > 1;
|
||||
component.backendApi.eachDataRow((rowIndex, row) => {
|
||||
const hasDesignDimension = cubes.design;
|
||||
const hasSecondDimension = hasDesignDimension ? dimensionsInformation.length > 2 : dimensionsInformation.length > 1;
|
||||
cubes.data.forEach(row => {
|
||||
lastRow += 1;
|
||||
const dimension1Entry = generateDimensionEntry(dimensionsInformation[0], row[0]);
|
||||
dimension1.push(dimension1Entry);
|
||||
@@ -167,7 +172,7 @@ function generateDataSet (component, dimensionsInformation, measurementsInformat
|
||||
};
|
||||
}
|
||||
|
||||
async function initializeTransformed ({ $element, layout, component }) {
|
||||
function initializeTransformed ({ $element, component, cubes, layout }) {
|
||||
const dimensionsInformation = component.backendApi.getDimensionInfos();
|
||||
const measurementsInformation = component.backendApi.getMeasureInfos();
|
||||
const dimensionCount = layout.qHyperCube.qDimensionInfo.length;
|
||||
@@ -178,37 +183,29 @@ async function initializeTransformed ({ $element, layout, component }) {
|
||||
dimension2,
|
||||
measurements,
|
||||
matrix
|
||||
} = generateDataSet(component, dimensionsInformation, measurementsInformation);
|
||||
} = generateDataSet(component, dimensionsInformation, measurementsInformation, cubes);
|
||||
|
||||
const customSchemaBasic = [];
|
||||
const customSchemaFull = [];
|
||||
let customHeadersCount = 0;
|
||||
|
||||
function readCustomSchema () {
|
||||
const url = `/Extensions/qlik-smart-pivot/${layout.customfile}`;
|
||||
if (cubes.design) {
|
||||
const allTextLines = cubes.design.map(entry => entry[0].qText);
|
||||
const headers = allTextLines[0].split(';');
|
||||
customHeadersCount = headers.length;
|
||||
for (let lineNumber = 0; lineNumber < allTextLines.length; lineNumber += 1) {
|
||||
customSchemaFull[lineNumber] = new Array(headers.length);
|
||||
const data = allTextLines[lineNumber].split(';');
|
||||
|
||||
return jQuery.get(url).then(response => {
|
||||
const allTextLines = response.split(/\r\n|\n/);
|
||||
const headers = allTextLines[0].split(';');
|
||||
customHeadersCount = headers.length;
|
||||
for (let lineNumber = 0; lineNumber < allTextLines.length; lineNumber += 1) {
|
||||
customSchemaFull[lineNumber] = new Array(headers.length);
|
||||
const data = allTextLines[lineNumber].split(';');
|
||||
|
||||
if (data.length === headers.length) {
|
||||
for (let headerIndex = 0; headerIndex < headers.length; headerIndex += 1) {
|
||||
customSchemaBasic[lineNumber] = data[0];
|
||||
customSchemaFull[lineNumber][headerIndex] = data[headerIndex];
|
||||
}
|
||||
if (data.length === headers.length) {
|
||||
for (let headerIndex = 0; headerIndex < headers.length; headerIndex += 1) {
|
||||
[customSchemaBasic[lineNumber]] = data;
|
||||
customSchemaFull[lineNumber][headerIndex] = data[headerIndex];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const hasCustomSchema = (layout.customfilebool && layout.customfile.length > 4);
|
||||
const schemaPromise = hasCustomSchema ? readCustomSchema() : Promise.resolve();
|
||||
await schemaPromise;
|
||||
|
||||
// top level properties could be reducers and then components connect to grab what they want,
|
||||
// possibly with reselect for some presentational transforms (moving some of the presentational logic like formatting and such)
|
||||
const transformedProperties = {
|
||||
@@ -242,7 +239,7 @@ async function initializeTransformed ({ $element, layout, component }) {
|
||||
count: customHeadersCount,
|
||||
full: customSchemaFull
|
||||
},
|
||||
hasCustomFileStyle: layout.customfilebool,
|
||||
hasCustomFileStyle: Boolean(cubes.design),
|
||||
headerOptions: {
|
||||
alignment: getAlignment(layout.HeaderAlign),
|
||||
colorSchema: layout.HeaderColorSchema.color,
|
||||
@@ -313,7 +310,6 @@ async function initializeTransformed ({ $element, layout, component }) {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
return transformedProperties;
|
||||
}
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
font-family: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,10 +80,11 @@
|
||||
// This is for wrap text in headers
|
||||
.wrapclass25 {
|
||||
width: 100%;
|
||||
height: 25px;
|
||||
height: inherit;
|
||||
white-space: pre-line;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.wrapclass45 {
|
||||
|
||||
@@ -2,11 +2,17 @@ import initializeStore from './store';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Root from './root.jsx';
|
||||
import { initializeCubes } from './dataset';
|
||||
|
||||
export default async function paint ($element, layout, component) {
|
||||
const cubes = await initializeCubes({
|
||||
component,
|
||||
layout
|
||||
});
|
||||
const state = await initializeStore({
|
||||
$element,
|
||||
component,
|
||||
cubes,
|
||||
layout
|
||||
});
|
||||
const editmodeClass = component.inAnalysisState() ? '' : 'edit-mode';
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import initializeTransformed from './initialize-transformed';
|
||||
|
||||
async function initialize ({ $element, layout, component }) {
|
||||
async function initialize ({ $element, layout, component, cubes }) {
|
||||
const transformedProperties = await initializeTransformed({
|
||||
$element,
|
||||
component,
|
||||
cubes,
|
||||
layout
|
||||
});
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ const handleCalculateTooltipPosition = (event) => {
|
||||
tooltip.style.left = `${event.clientX}px`;
|
||||
tooltip.style.top = `${event.clientY}px`;
|
||||
};
|
||||
class Tooltip extends React.Component {
|
||||
|
||||
class Tooltip extends React.PureComponent {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
@@ -18,20 +19,11 @@ class Tooltip extends React.Component {
|
||||
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;
|
||||
@@ -60,7 +52,11 @@ class Tooltip extends React.Component {
|
||||
}
|
||||
|
||||
Tooltip.propTypes = {
|
||||
children: PropTypes.string.isRequired,
|
||||
children: PropTypes.oneOfType([
|
||||
PropTypes.arrayOf(PropTypes.node),
|
||||
PropTypes.node
|
||||
]).isRequired,
|
||||
tooltipText: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
export default Tooltip;
|
||||
|
||||
@@ -13,13 +13,15 @@ const config = {
|
||||
commonjs: 'jquery',
|
||||
commonjs2: 'jquery',
|
||||
root: '_'
|
||||
},
|
||||
qlik: {
|
||||
amd: 'qlik',
|
||||
commonjs: 'qlik',
|
||||
commonjs2: 'qlik',
|
||||
root: '_'
|
||||
}
|
||||
},
|
||||
mode: settings.mode,
|
||||
// TODO: breaks core-js for some reason
|
||||
// resolve: {
|
||||
// extensions: ['js', 'jsx']
|
||||
// },
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
@@ -68,12 +70,7 @@ const config = {
|
||||
`assets/${settings.name}.qext`,
|
||||
`assets/${settings.name}.png`,
|
||||
'assets/wbfolder.wbl',
|
||||
'resources/Excel.png',
|
||||
|
||||
// TODO: remove entries below this line
|
||||
'resources/Accounts.csv',
|
||||
'resources/Accounts2.csv',
|
||||
'resources/QlikLook.csv'
|
||||
'resources/Excel.png'
|
||||
], {}),
|
||||
new StyleLintPlugin({
|
||||
files: '**/*.less'
|
||||
|
||||
Reference in New Issue
Block a user