Compare commits

...

8 Commits

Author SHA1 Message Date
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
71cf92c217 Slider for cell width without presets
-Previous slider only has three presets, this new
 solution sets the actual width.

Issue: DEB-221
2019-05-27 14:08:25 +02:00
Albert Backenhof
20282b0b99 Merge pull request #65 from qlik-oss/QLIK-95907/QlikFormatting
Using qlik formatting measurements
2019-05-20 10:05:48 +02:00
Albert Backenhof
5f18321ccf Merge pull request #67 from qlik-oss/DEB-136/readme
Updated github readme
2019-05-20 09:07:54 +02:00
Albert Backenhof
d14f5951ac Using qlik formatting measurements
Issue: QLIK-95907
2019-05-20 08:02:15 +02:00
Albert Backenhof
5872ee7b58 Updated github readme
Issue: DEB-136
2019-05-20 07:02:45 +02:00
Purwa Shrivastava
6d305b21b2 Merge pull request #60 from qlik-oss/revert-59-DEB-217/CellFormatting
Revert "Fixed cell number formatting"
2019-05-10 12:48:04 +02:00
Purwa Shrivastava
0b210e0d35 Revert "Fixed cell number formatting" 2019-05-10 12:44:32 +02:00
8 changed files with 42 additions and 179 deletions

View File

@@ -1,52 +1,22 @@
# P&L Smart Pivot, a Qlik Sense Extension for Financial reporting
[![CircleCI](https://circleci.com/gh/qlik-oss/PLSmartPivot.svg?style=svg)](https://circleci.com/gh/qlik-oss/PLSmartPivot)
This extension is part of the extension bundles for Qlik Sense. The repository is maintained and moderated by Qlik RD.
This extension is useful to create reports where the look&feel is rellevantand and pivot a second dimension is needed. Based on P&L Smart.
It's specifically focused on financial reports, trying to solve some common needs of this area:
- smart export to excel
- easy creation of reports
- custom corporate reporting (bold, italic, background color, letter size, headers,...)
- selections inside the reports
- custom external templates
- analytical reports
# Manual
You'll find a manual [Qlik Sense P&LSmart Pivot Extension Manual.pdf](resources/Qlik Sense P&LSmart Pivot Extension Manual.pdf) and one app example [P&LSmartPivot_demo.qvf](resources/P&LSmartPivot_demo.qvf).
# Installation
1. Download the extension zip, `qlik-smart-pivot_<version>.zip`, from the latest release(https://github.com/qlik-oss/PLSmartPivot/releases/latest)
2. Install the extension:
a. **Qlik Sense Desktop**: unzip to a directory under [My Documents]/Qlik/Sense/Extensions.
b. **Qlik Sense Server**: import the zip file in the QMC.
Feel free to fork and suggest pull requests for improvements and bug fixes. Changes will be moderated and reviewed before inclusion in future bundle versions. Please note that emphasis is on backward compatibility, i.e. breaking changes will most likely not be approved.
Usage documentation for the extension is available at https://help.qlik.com.
# Developing the extension
If you want to do code changes to the extension follow these simple steps to get going.
1. Get Qlik Sense Desktop
1. Create a new app and add the extension to a sheet.
1. Create a new app and add P&L pivot to a sheet.
2. Clone the repository
3. Run `npm install`
4. Set the environment variable `BUILD_PATH` to your extensions directory. It will be something like `C:/Users/<user>/Documents/Qlik/Sense/Extensions/<extension_name>`.
5. You now have two options. Either run the watch task or the build task. They are explained below. Both of them default to development mode but can be run in production by setting `NODE_ENV=production` before running the npm task.
a. **Watch**: `npm run watch`. This will start a watcher which will rebuild the extension and output all needed files to the `buildFolder` for each code change you make. See your changes directly in your Qlik Sense app.
b. **Build**: `npm run build`. If you want to build the extension package. The output zip-file can be found in the `buildFolder`.
4. Run `npm run build` - to build a dev-version to the /dist folder.
5. Move the content of the /dist folder to the extension directory. Usually in `C:/Users/<user>/Documents/Qlik/Sense/Extensions/qlik-smart-pivot`.
# Original authors
[github.com/iviasensio](https://github.com/iviasensio)
# License
Released under the [MIT License](LICENSE).
Released under the [MIT License](LICENSE).

View File

@@ -24,7 +24,6 @@ class DataCell extends React.PureComponent {
render () {
const {
data,
general,
measurement,
styleBuilder,
@@ -37,15 +36,18 @@ class DataCell extends React.PureComponent {
fontFamily: styling.options.fontFamily,
...styleBuilder.getStyle(),
paddingLeft: '5px',
textAlign: textAlignment
textAlign: textAlignment,
minWidth: general.cellWidth,
maxWidth: general.cellWidth
};
const isEmptyCell = measurement.displayValue === '';
const isColumnPercentageBased = (/%/).test(measurement.format);
let formattedMeasurementValue;
if (isEmptyCell || styleBuilder.hasComments()) {
if (isEmptyCell) {
formattedMeasurementValue = '';
cellStyle.cursor = 'default';
} else if (styleBuilder.hasComments()) {
formattedMeasurementValue = '.';
} else {
formattedMeasurementValue = formatMeasurementValue(measurement, styling);
}
@@ -66,16 +68,9 @@ class DataCell extends React.PureComponent {
}
}
let cellClass = 'grid-cells';
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';
}
return (
<td
className={`${cellClass}${general.cellSuffix}`}
className="grid-cells"
onClick={isEmptyCell ? null : this.handleSelect}
style={cellStyle}
>
@@ -97,7 +92,7 @@ DataCell.propTypes = {
}).isRequired
}).isRequired,
general: PropTypes.shape({
cellSuffix: PropTypes.string.isRequired
cellWidth: PropTypes.string.isRequired
}).isRequired,
measurement: PropTypes.shape({
format: PropTypes.string,
@@ -127,9 +122,9 @@ export default DataCell;
function formatMeasurementValue (measurement, styling) {
if (isNaN(measurement.value)) {
return styling.symbolForNulls;
} else {
return measurement.displayValue;
}
return measurement.displayValue;
}
function getConditionalColor (measurement, conditionalColoring) {

View File

@@ -214,10 +214,10 @@ const tableFormat = {
component: 'slider',
label: 'Column width',
ref: 'columnwidthslider',
min: 1,
max: 3,
step: 1,
defaultValue: 2
min: 20,
max: 250,
step: 10,
defaultValue: 50
},
SymbolForNulls: {
ref: 'symbolfornulls',

View File

@@ -15,7 +15,7 @@ class ColumnHeader extends React.PureComponent {
}
render () {
const { baseCSS, cellSuffix, colSpan, entry, styling, qlik } = this.props;
const { baseCSS, cellWidth, colSpan, entry, styling, qlik } = this.props;
const inEditState = qlik.inEditState();
const isMediumFontSize = styling.headerOptions.fontSizeAdjustment === HEADER_FONT_SIZE.MEDIUM;
@@ -23,12 +23,14 @@ class ColumnHeader extends React.PureComponent {
...baseCSS,
fontSize: `${14 + styling.headerOptions.fontSizeAdjustment}px`,
height: isMediumFontSize ? '43px' : '33px',
verticalAlign: 'middle'
verticalAlign: 'middle',
minWidth: cellWidth,
maxWidth: cellWidth
};
return (
<th
className={`grid-cells2${cellSuffix}`}
className="grid-cells"
colSpan={colSpan}
onClick={this.handleSelect}
style={style}
@@ -46,13 +48,12 @@ class ColumnHeader extends React.PureComponent {
}
ColumnHeader.defaultProps = {
cellSuffix: '',
colSpan: 1
};
ColumnHeader.propTypes = {
baseCSS: PropTypes.shape({}).isRequired,
cellSuffix: PropTypes.string,
cellWidth: PropTypes.string,
colSpan: PropTypes.number,
entry: PropTypes.shape({
elementNumber: PropTypes.number.isRequired,

View File

@@ -68,7 +68,7 @@ const HeadersTable = ({ data, general, qlik, styling, isKpi }) => {
return (
<ColumnHeader
baseCSS={baseCSS}
cellSuffix={general.cellSuffix}
cellWidth={general.cellWidth}
colSpan={measurements.length}
entry={entry}
key={entry.displayValue}

View File

@@ -4,27 +4,27 @@ 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 title = `${measurement.name}`;
const { fontSizeAdjustment } = styling.headerOptions;
const isMediumFontSize = fontSizeAdjustment === HEADER_FONT_SIZE.MEDIUM;
if (hasSecondDimension) {
const isPercentageFormat = measurement.format.substring(measurement.format.length - 1) === '%';
let baseFontSize = 14;
let cellClass = 'grid-cells2';
if (isPercentageFormat) {
baseFontSize = 13;
cellClass = 'grid-cells2-small';
}
const cellStyle = {
...baseCSS,
fontSize: `${baseFontSize + fontSizeAdjustment}px`,
height: isMediumFontSize ? '45px' : '35px',
verticalAlign: 'middle'
verticalAlign: 'middle',
minWidth: general.cellWidth,
maxWidth: general.cellWidth
};
return (
<th
className={`${cellClass}${general.cellSuffix}`}
className="grid-cells"
style={cellStyle}
>
<Tooltip
@@ -41,11 +41,13 @@ const MeasurementColumnHeader = ({ baseCSS, general, hasSecondDimension, measure
...baseCSS,
fontSize: `${15 + fontSizeAdjustment}px`,
height: isMediumFontSize ? '90px' : '70px',
verticalAlign: 'middle'
verticalAlign: 'middle',
minWidth: general.cellWidth,
maxWidth: general.cellWidth
};
return (
<th
className={`grid-cells2${general.cellSuffix}`}
className="grid-cells"
style={style}
>
<Tooltip
@@ -65,7 +67,7 @@ MeasurementColumnHeader.defaultProps = {
MeasurementColumnHeader.propTypes = {
baseCSS: PropTypes.shape({}).isRequired,
general: PropTypes.shape({
cellSuffix: PropTypes.string.isRequired
cellWidth: PropTypes.string.isRequired
}).isRequired,
hasSecondDimension: PropTypes.bool,
measurement: PropTypes.shape({

View File

@@ -24,40 +24,10 @@ function getFontSizeAdjustment (option) {
return fontSizeAdjustmentOptions[option] || 0;
}
function getCellSuffix (option) {
const cellSuffixOptions = {
1: '-s',
3: '-l'
};
return cellSuffixOptions[option] || '';
}
function getMeasurementFormat (measurement) {
if (measurement.qNumFormat.qType === 'U' || measurement.qNumFormat.qFmt === '##############') {
return '#.##0';
} else if (measurement.qNumFormat.qType === 'R') {
return measurement.qNumFormat.qFmt.replace(/(|)/gi, '');
}
return measurement.qNumFormat.qFmt;
}
function getMagnitudeLabelSuffix (magnitudeOption) {
const magnitudeLabelSuffixOptions = {
'k': ' (k)',
'm': ' (m)'
};
return magnitudeLabelSuffixOptions[magnitudeOption] || '';
}
function generateMeasurements (information) {
return information.map(measurement => {
const format = getMeasurementFormat(measurement);
const formatMagnitude = format.substr(format.length - 1).toLowerCase();
const transformedMeasurement = {
format,
magnitudeLabelSuffix: getMagnitudeLabelSuffix(formatMagnitude),
format: measurement.qNumFormat.qFmt || '#.##0',
name: measurement.qFallbackTitle
};
@@ -78,11 +48,6 @@ function generateMatrixCell ({ cell, dimension1Information, dimension2Informatio
const matrixCell = {
displayValue: cell.qText,
format: measurementInformation.format,
magnitude: measurementInformation.magnitudeLabelSuffix.substring(
measurementInformation.magnitudeLabelSuffix.length - 2,
measurementInformation.magnitudeLabelSuffix.length - 1
),
magnitudeLabelSuffix: measurementInformation.magnitudeLabelSuffix,
name: measurementInformation.name,
parents: {
dimension1: {
@@ -279,7 +244,8 @@ function initializeTransformed ({ $element, component, dataCube, designList, lay
general: {
allowExcelExport: layout.allowexportxls,
allowFilteringByClick: layout.filteroncellclick,
cellSuffix: getCellSuffix(layout.columnwidthslider), // TOOD: move to matrix cells or is it headers.measurements?
// If using the previous solution just set 60px
cellWidth: `${layout.columnwidthslider > 10 ? layout.columnwidthslider : 60}px`,
errorMessage: layout.errormessage,
footnote: layout.footnote,
maxLoops,

View File

@@ -12,9 +12,7 @@
pointer-events: none;
}
._cell(@Width: 50px) {
min-width: @Width !important;
max-width: @Width !important;
.grid-cells {
cursor: pointer;
line-height: 1em !important;
}
@@ -74,67 +72,6 @@
text-align: right;
}
// *****************
// Medium column size
// *****************
.grid-cells {
position: relative;
._cell(70px);
}
.grid-cells2 {
._cell(70px);
}
.grid-cells-small {
._cell(52px);
}
.grid-cells2-small {
._cell(52px);
}
// *****************
// Small column size
// *****************
.grid-cells-s {
._cell(67px);
}
.grid-cells2-s {
._cell(67px);
}
.grid-cells-small-s {
._cell(52px);
}
.grid-cells2-small-s {
._cell(52px);
}
// *****************
// Large column size
// *****************
.grid-cells-l {
._cell(82px);
}
.grid-cells2-l {
._cell(82px);
}
.grid-cells-small-l {
._cell(66px);
}
.grid-cells2-small-l {
._cell(66px);
}
// END OF GRID CELLS
// First Column
.fdim-cells {
min-width: 230px !Important;
@@ -149,14 +86,6 @@
color: #fff;
}
.grid-cells-header {
padding: 0;
}
.grid-cells-title {
min-width: 522px;
}
.grid {
height: 50px;
width: 350px;