Compare commits

...

52 Commits

Author SHA1 Message Date
Albert Backenhof
ca33540fd6 Merge pull request #35 from qlik-oss/DEB-152/HeaderWidth
The header width should match the table format
2019-04-10 09:13:03 +02:00
Albert Backenhof
629821bd6b The header width should match the table format
Issue: DEB-152
2019-04-08 10:39:02 +02:00
Albert Backenhof
08c5cf8104 Merge pull request #34 from qlik-oss/DEB-130/VersionInDesc
Aligned build to how Dashboard bundle extensions
2019-04-05 14:40:13 +02:00
Tobias Åström
d3c39bea75 Merge pull request #32 from qlik-oss/tsm-color-picker-check
Update metric-semaphores.js
2019-04-05 13:46:58 +02:00
Albert Backenhof
141be3f962 Aligned build to Dashboard bundle extensions build
-Part of the work to streamline how the extensions
 are handled, irregardless of what bundle.

Issue: DEB-130, DEB-133
2019-03-27 09:53:09 +01:00
Albert Backenhof
433a725f33 Merge pull request #33 from qlik-oss/snapshotFix
New preview image and fixed snapshot
2019-03-20 10:28:52 +01:00
Albert Backenhof
769d5cfa3f New preview image and fixed snapshot
-SnapshotApi doesn't have a getProperties
 so fetching the source properties from
 qlik-app instead.

-The snapshot still cannot be rendered in the
 "printing-snapshot" test page because of
 limitations on that page.
2019-03-19 10:38:29 +01:00
Albert Backenhof
9d925b6205 Merge pull request #29 from qlik-oss/feature/QPE-427
[QPE-427] Replace csv styling with dimension styling
2019-03-18 06:57:13 +01:00
Tobias Åström
34527c3d6d Update metric-semaphores.js
We recently had a bug on the color picker when used in extensions (QLIK-94131) so I went through all extensions to check their status, this was the only one with a potential problem.
The property notation should be as I changed it now (but after fixing the bug it will work anyway). However, there might be code elsewhere in the extension that mitigates the bug, so make sure this gets tested.
2019-03-12 09:04:43 +01:00
Kristoffer Lind
35d489c2e2 add updated demo app 2019-02-28 15:58:14 +01:00
Kristoffer Lind
9ef9981305 remove demo app 2019-02-28 15:56:44 +01:00
Kristoffer Lind
398192e057 fix indent and hide when design dimension is applied 2019-02-28 15:36:56 +01:00
Kristoffer Lind
4421217cb0 set default for metric semaphores to apply to nothing 2019-02-28 15:36:56 +01:00
Kristoffer Lind
c92be00ca7 update app with corrected colors for sheet 4 2019-02-28 15:36:56 +01:00
Kristoffer Lind
c66dfdc06c only show row colors when it does not have design dimension 2019-02-28 15:36:55 +01:00
Kristoffer Lind
a882b1d6aa update demo app so its no longer saved with faulty colors 2019-02-28 15:36:55 +01:00
Kristoffer Lind
554b029569 remove unused options include external csv file and path 2019-02-28 15:36:55 +01:00
Kristoffer Lind
4a15628325 remove csv files 2019-02-28 15:36:55 +01:00
Kristoffer Lind
fdb2aaaef4 use originHyperCubeDefinition as basis for dynamically created hyperCubes 2019-02-28 15:36:55 +01:00
Kristoffer Lind
a400e9c233 use createDimension for design cube aswell 2019-02-28 15:36:55 +01:00
Kristoffer Lind
091c564a75 apply styling from dimension 2019-02-28 15:36:54 +01:00
Kristoffer Lind
99eba8afcb split qHyperCube into two cubes, one for data and one for design 2019-02-28 15:36:54 +01:00
giovanni hanselius
cb78a2f2f9 Merge pull request #31 from qlik-oss/QPE-637-header-format-fixes
[QPE 637] Header format fixes
2019-02-28 12:48:09 +01:00
Balazs Gobel
f255efbf5d Handle medium header font size better and prevent cutting text off 2019-02-28 12:40:29 +01:00
giovanni hanselius
2f2d08fedd Merge pull request #30 from qlik-oss/QPE-636-table-format-fixes
[QPE 636] Table format fixes
2019-02-28 11:02:46 +01:00
Balazs Gobel
ac8b70bc84 Use correct fallback for all fonts 2019-02-28 10:49:24 +01:00
giovanni hanselius
0f2a4f9805 Merge pull request #27 from qlik-oss/QPE-631-IE-errors
[QPE 631] Prevent console errors in IE on cell hover
2019-02-28 09:33:55 +01:00
Balazs Gobel
85228412cc show correct color in the color picker 2019-02-27 21:43:09 +01:00
Balazs Gobel
03dfc0ce93 prevent infinite loop in angular color picker
- dualOutput must be the last line
2019-02-27 21:39:59 +01:00
Balazs Gobel
48427df559 enable changing font size in headers 2019-02-27 21:39:31 +01:00
Balazs Gobel
7fda7aa2d9 better defaults when missing font family 2019-02-27 20:54:50 +01:00
Balazs Gobel
4ba12b8b2d show user-selected font-family for the cells 2019-02-27 20:51:18 +01:00
Balazs Gobel
07af7b509e Make table format work again
- working color picker
 - working font size
 - working cell text alignment
 - this is all by preventing the infinite loop in angular
2019-02-27 20:45:06 +01:00
Balazs Gobel
b7ff83e1da prevent console errors in IE on cell hover 2019-02-27 20:37:02 +01:00
giovanni hanselius
621359d6f9 Merge pull request #28 from qlik-oss/QPE-634-column-width-fix
[QPE 634] Fix column width
2019-02-27 15:06:04 +01:00
Balazs Gobel
a71f80f8fa minor cleanup 2019-02-27 14:26:27 +01:00
Balazs Gobel
a6cbfcda70 Fix column width issue
- Look at the value format to determine if column is percentage based
2019-02-27 14:25:50 +01:00
giovanni hanselius
de2e9c16ac Merge pull request #25 from qlik-oss/QPE-549-tooltip-design
[QPE 549] Minor adjustments for tooltip
2019-02-27 12:30:42 +01:00
giovanni hanselius
ad0c0dacba Merge pull request #24 from qlik-oss/QPE-622-visible-scrollbar
[QPE 622] show scrollbar for easier scrolling
2019-02-27 11:14:01 +01:00
giovanni hanselius
97564cf8b1 Merge pull request #26 from qlik-oss/QPE-600-same-padding-in-single-object-mode
[QPE 600] Use same layout in single onject mode as in normal mode
2019-02-27 11:03:33 +01:00
Balazs Gobel
7fa44c06b0 Use same layout in single onject mode as in normal mode
- same padding for single object mode
2019-02-26 16:02:40 +01:00
Balazs Gobel
dae192b7af Minor adjustments for tooltip
- Added tooltip for row header
- Better vertical alignment
- Move static styling to css
2019-02-26 15:44:17 +01:00
Balazs Gobel
5abfd5b7e5 show scrollbar for easier scrolling 2019-02-26 15:10:00 +01:00
giovanni hanselius
65f5d70654 Merge pull request #23 from qlik-oss/feature/QPE-615
[QPE-615] fix metric semaphore colors
2019-02-26 14:34:17 +01:00
Kristoffer Lind
da7ba5c3a8 fix default indexes for metric colors 2019-02-26 14:23:42 +01:00
Kristoffer Lind
6e5df323d8 update sample state 2019-02-26 11:37:31 +01:00
Kristoffer Lind
aad92678db fix metric semaphore colors 2019-02-26 11:31:24 +01:00
giovanni hanselius
15226d8598 Merge pull request #17 from qlik-oss/QPE-426
[QPE-426] color pickers
2019-02-25 15:25:29 +01:00
Balazs Gobel
a5fc586859 Merge branch 'master' into QPE-426 2019-02-25 15:14:13 +01:00
Kristoffer Lind
a25b2c40c0 removed a few more pieces of the colors library 2019-02-22 14:30:18 +01:00
ahmed-Bazzara
46d6520273 update app added
colors set to have a fallback value
2019-02-22 14:29:23 +01:00
ahmed-Bazzara
19286f6c56 color libraries deleted and Qlik's color-pickers introduced 2019-02-22 14:29:23 +01:00
42 changed files with 590 additions and 3548 deletions

View File

@@ -26,9 +26,6 @@ jobs:
--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
bump-version:
<<: *defaults
@@ -56,16 +53,18 @@ jobs:
command: |
export VERSION=$(scripts/get-bumped-version.sh)
echo "Version: ${VERSION}"
npm run build
npm run build:zip
sudo chmod +x scripts/verify-files.sh
scripts/verify-files.sh
environment:
NODE_ENV: production
- persist_to_workspace:
root: ~/qlik-smart-pivot
paths:
- build
- dist
- store_artifacts:
path: build
destination: build
path: dist
destination: dist
deploy:
<<: *defaults
steps:

2
.gitignore vendored
View File

@@ -19,7 +19,7 @@ $RECYCLE.BIN/
# Temporary build files
node_modules/
build/
dist/
BUMPED_VERSION
# =========================

View File

@@ -16,11 +16,6 @@ It's specifically focused on financial reports, trying to solve some common need
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).
# If the import does not work at first time
- remove [Accounts.csv](resources/Accounts.csv), [Accounts2.csv](resources/Accounts2.csv) and [Excel.png](resources/Excel.png), zip it again and import.
- Then reintroduce [Accounts.csv](resources/Accounts.csv), [Accounts2.csv](resources/Accounts2.csv) and [Excel.png](resources/Excel.png), zip it again and import.
# Installation
1. Download the extension zip, `qlik-smart-pivot_<version>.zip`, from the latest release(https://github.com/qlik-oss/PLSmartPivot/releases/latest)

View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 123 B

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

@@ -1,16 +0,0 @@
{
"name": "P&L pivot",
"description": "Profit & Loss reporting with color and font customizations.",
"type": "visualization",
"version": "X.Y.Z",
"icon": "table",
"preview": "",
"author": "Ivan Felipe Asensio <ivan.felipe@qlik.com>",
"homepage": "",
"keywords": "qlik-sense, visualization",
"license": "MIT",
"repository": "https://github.com/qlik-oss/PLSmartPivot",
"dependencies": {
"qlik-sense": ">=5.5.x"
}
}

View File

@@ -1,3 +0,0 @@
qlik-smart-pivot.js;
qlik-smart-pivot.css;
qlik-smart-pivot.qext

View File

@@ -1,23 +1,61 @@
var gulp = require('gulp');
var gutil = require('gulp-util');
var zip = require('gulp-zip');
var del = require('del');
var path = require('path');
var settings = require('./settings');
var webpackConfig = require('./webpack.config');
var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var jeditor = require("gulp-json-editor");
var pkg = require('./package.json');
var srcFiles = path.resolve('./src/**/*.*');
var DIST = './dist';
var VERSION = process.env.VERSION || 'local-dev';
gulp.task('remove-build-folder', function(){
return del([settings.buildDestination], { force: true });
gulp.task('qext', function () {
var qext = {
name: 'P&L pivot',
type: 'visualization',
description: pkg.description + '\nVersion: ' + VERSION,
version: VERSION,
icon: 'table',
preview: 'qlik-smart-pivot.png',
keywords: 'qlik-sense, visualization',
author: pkg.author,
homepage: pkg.homepage,
license: pkg.license,
repository: pkg.repository,
dependencies: {
'qlik-sense': '>=5.5.x'
}
};
if (pkg.contributors) {
qext.contributors = pkg.contributors;
}
var src = require('stream').Readable({
objectMode: true
});
src._read = function () {
this.push(new gutil.File({
cwd: '',
base: '',
path: pkg.name + '.qext',
contents: Buffer.from(JSON.stringify(qext, null, 4))
}));
this.push(null);
};
return src.pipe(gulp.dest(DIST));
});
gulp.task('clean', function(){
return del([DIST], { force: true });
});
gulp.task('zip-build', function(){
return gulp.src(settings.buildDestination + '/**/*')
.pipe(zip(`${settings.name}_${settings.version}.zip`))
.pipe(gulp.dest(settings.buildDestination));
return gulp.src(DIST + '/**/*')
.pipe(zip(`${pkg.name}_${VERSION}.zip`))
.pipe(gulp.dest(DIST));
});
gulp.task('add-assets', function(){
return gulp.src('./assets/**/*').pipe(gulp.dest(DIST));
});
gulp.task('webpack-build', done => {
@@ -36,40 +74,14 @@ gulp.task('webpack-build', done => {
});
});
gulp.task('update-qext-version', function () {
return gulp.src(`${settings.buildDestination}/${settings.name}.qext`)
.pipe(jeditor({
'version': settings.version
}))
.pipe(gulp.dest(settings.buildDestination));
});
gulp.task('build',
gulp.series('remove-build-folder', 'webpack-build', 'update-qext-version', 'zip-build')
gulp.series('clean', 'webpack-build', 'qext', 'add-assets')
);
gulp.task('zip',
gulp.series('build', 'zip-build')
);
gulp.task('default',
gulp.series('build')
);
gulp.task('watch', () => new Promise((resolve, reject) => {
webpackConfig.entry.unshift('webpack-dev-server/client?http://localhost:' + settings.port);
const compiler = webpack(webpackConfig);
const originalOutputFileSystem = compiler.outputFileSystem;
const devServer = new WebpackDevServer(compiler, {
headers: {
"Access-Control-Allow-Origin": "*"
},
}).listen(settings.port, 'localhost', error => {
compiler.outputFileSystem = originalOutputFileSystem;
if (error) {
console.error(error); // eslint-disable-line no-console
return reject(error);
}
// eslint-disable-next-line no-console
console.log('Listening at localhost:' + settings.port);
resolve(null, devServer);
});
}));

View File

@@ -1,69 +0,0 @@
const path = require('path');
const settings = require('./settings');
module.exports = (config) => {
config.set({
browsers: ['SlimChromeHeadless'],
customLaunchers: {
SlimChromeHeadless: {
base: 'ChromeHeadless',
flags: [
'--headless',
'--disable-gpu',
'--disable-translate',
'--disable-extensions'
]
}
},
files: [
{
pattern: 'src/**/*.spec.js',
watched: true
}
],
frameworks: ['jasmine'],
preprocessors: {
'src/**/*.spec.{js, jsx}': [
'webpack',
'sourcemap'
]
},
webpack: {
devtool: 'source-map',
externals: {
jquery: {
amd: 'jquery',
commonjs: 'jquery',
commonjs2: 'jquery',
root: '_'
}
},
mode: settings.mode,
module: {
rules: [
{
exclude: [/node_modules/],
loader: 'babel-loader',
options: {
plugins: [
'@babel/plugin-transform-async-to-generator',
'@babel/plugin-proposal-class-properties'],
presets: ['@babel/preset-react']
},
test: /\.(js|jsx)$/
},
{
loader: 'ignore-loader',
test: /\.less$/
}
]
},
resolve: {
alias: {
'test-utilities': path.resolve('test/test-utilities')
},
modules: ['node_modules']
}
}
});
};

2633
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,18 +1,15 @@
{
"name": "qlik-smart-pivot",
"version": "0.0.1",
"description": "Formatted table for P&L reports.",
"keywords": "smart pivot qliksense extension",
"description": "Profit & Loss reporting with color and font customizations.",
"homepage": "",
"repository": "https://github.com/iviasensio/PLSmartPivot",
"author": "Ivan Felipe Asensio <ivan.felipe@qlik.com>",
"license": "MIT",
"scripts": {
"build": "gulp build",
"build:zip": "gulp zip",
"eslint": "eslint src",
"eslint:fix": "eslint --fix src",
"test": "karma start karma.conf.js",
"test-once": "karma start karma.conf.js --single-run",
"watch": "gulp watch",
"stylelint": "stylelint src/main.less"
},
"devDependencies": {
@@ -24,7 +21,6 @@
"@babel/preset-react": "7.0.0",
"babel-eslint": "10.0.1",
"babel-loader": "8.0.4",
"copy-webpack-plugin": "4.5.3",
"css-loader": "1.0.0",
"del": "2.0.2",
"enzyme": "3.8.0",
@@ -33,15 +29,8 @@
"eslint-loader": "2.1.1",
"eslint-plugin-react": "7.11.1",
"gulp": "4.0.0",
"gulp-json-editor": "2.4.3",
"gulp-util": "^3.0.7",
"gulp-zip": "3.0.2",
"jasmine-core": "3.2.1",
"jasmine-enzyme": "7.0.1",
"karma": "3.0.0",
"karma-chrome-launcher": "2.2.0",
"karma-jasmine": "1.1.2",
"karma-sourcemap-loader": "0.3.7",
"karma-webpack": "3.0.5",
"less": "3.8.1",
"less-loader": "4.1.0",
"lodash.merge": "4.6.1",
@@ -49,9 +38,7 @@
"stylelint": "8.4.0",
"stylelint-webpack-plugin": "0.10.5",
"text-loader": "0.0.1",
"webpack": "4.20.2",
"webpack-cli": "3.1.2",
"webpack-dev-server": "3.1.10"
"webpack": "4.20.2"
},
"dependencies": {
"prop-types": "15.6.2",

View File

@@ -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>;<soft>;;;;;
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>;<violete>;;;;;
Net costs of goods sold;<bold>;<violete>;;;;;
Gross profit;<bold>;<dark>;;;<center>;<large>;
Operating expenses;<bold>;;<italic>;;;;
Selling expenses;;;;;;;
Sales salaries;;;;;;;
Warranty expenses;;;;;;;
Depreciation, store equipment;;;;;;;
Other selling expenses3;;;;;;;
Total selling expenses;<bold>;<violete>;;;;;
General & administrative expenses;;#b7dbff;<italic>;;<center>;;<comment>
Administration salaries;;;;;;;
Rent expenses;;;;;;;
Depreciation, computers;;;;;;;
Other general & admin expenses;;;;;;;
total general & admin expenses;<bold>;<soft>;;;;;
total operating expenses;<bold>;<violete>;;;;;
Operating income before taxes;<bold>;<dark>;;<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>;<dark>;;<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>;<soft>;;;;;
Less income tax on gain;;;;;;;
Extraordinary items after tax;<bold>;<soft>;;;;;
Net Income (Profit);<bold>;<dark>;;<white>;<center>;<large>;
1 Accounts Bold Background FontStyle LetterColor Align Size Comment
2 Revenues rgb(183, 219, 255) <italic> <center> <comment>
3 Gross sales revenues
4 Less return & allowances
5 Net sales revenues <bold> <soft>
6 Cost of goods sold <bold>
7 Direct materials
8 Direct labor
9 Manufacturing overhead #b7dbff <italic> <center> <comment>
10 Indirect labor
11 Depreciation, manufacturing equip
12 Other mfr overhead
13 Net mfr overhead <bold> <violete>
14 Net costs of goods sold <bold> <violete>
15 Gross profit <bold> <dark> <center> <large>
16 Operating expenses <bold> <italic>
17 Selling expenses
18 Sales salaries
19 Warranty expenses
20 Depreciation, store equipment
21 Other selling expenses3
22 Total selling expenses <bold> <violete>
23 General & administrative expenses #b7dbff <italic> <center> <comment>
24 Administration salaries
25 Rent expenses
26 Depreciation, computers
27 Other general & admin expenses
28 total general & admin expenses <bold> <soft>
29 total operating expenses <bold> <violete>
30 Operating income before taxes <bold> <dark> <white> <large>
31 Financial revenue & expenses #b7dbff <italic> <center> <comment>
32 Revenue from investments
33 Less interest expenses
34 Net financial gain (expense)
35 Income before tax & extraordinary items <bold> <dark> <white> <large>
36 Less income tax on operations
37 Income before extraordinary items
38 Extraordinary items #b7dbff <italic> <center> <comment>
39 Sale of land
40 Less initial cost
41 Net gain on sale of land <bold> <soft>
42 Less income tax on gain
43 Extraordinary items after tax <bold> <soft>
44 Net Income (Profit) <bold> <dark> <white> <center> <large>

View File

@@ -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>;<soft>;;;;;
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>;<night>;;<white>;<center>;<large>;
1 Accounts Bold Background FontStyle LetterColor Align Size Comment
2 Revenues <bold> <italic> <center> <comment>
3 Net sales revenues <bold> rgb(128, 191, 255)
4 Cost of goods sold <bold> rgb(128, 191, 255)
5 Manufacturing overhead <bold> <italic> <center> <comment>
6 Net mfr overhead <bold> rgb(128, 191, 255)
7 Net costs of goods sold <bold> rgb(128, 191, 255)
8 Gross profit <bold> rgb(0, 102, 204) <white> <center> <large>
9 Operating expenses <bold> <italic>
10 Total selling expenses <bold> rgb(128, 191, 255)
11 General & administrative expenses <bold> <italic> <center> <comment>
12 Other general & admin expenses <bold> rgb(128, 191, 255) <white> <center> <large>
13 total general & admin expenses <bold> <soft>
14 total operating expenses <bold> rgb(128, 191, 255)
15 Operating income before taxes <bold> rgb(0, 102, 204) <white> <large>
16 Financial revenue & expenses <bold> <italic> <center> <comment>
17 Income before tax & extraordinary items <bold> rgb(0, 102, 204) <white> <large>
18 Extraordinary items <bold> <italic> <center> <comment>
19 Net gain on sale of land <bold> rgb(0, 102, 204) <white> <center> <large>
20 Extraordinary items after tax <bold> rgb(0, 102, 204) <white> <center> <large>
21 Net Income (Profit) <bold> <night> <white> <center> <large>

Binary file not shown.

View File

@@ -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>;<soft>;;;;;
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>;<night>;;<white>;<center>;<large>;
1 Accounts Bold Background FontStyle LetterColor Align Size Comment
2 Revenues <bold> <italic> <center> <comment>
3 Net sales revenues <bold> RGB(225,226,226)
4 Cost of goods sold <bold> RGB(225,226,226)
5 Manufacturing overhead <bold> <italic> <center> <comment>
6 Net mfr overhead <bold> RGB(225,226,226)
7 Net costs of goods sold <bold> RGB(225,226,226)
8 Gross profit <bold> RGB(193,216,47) <center> <large>
9 Operating expenses <bold> <italic>
10 Total selling expenses <bold> RGB(225,226,226)
11 General & administrative expenses <bold> <italic> <center> <comment>
12 Other general & admin expenses <bold> rgb(128, 191, 255) <white> <center> <large>
13 total general & admin expenses <bold> <soft>
14 total operating expenses <bold> rgb(128, 191, 255) <white>
15 Operating income before taxes <bold> RGB(193,216,47) <large>
16 Financial revenue & expenses <bold> <italic> <center> <comment>
17 Income before tax & extraordinary items <bold> RGB(193,216,47) <large>
18 Extraordinary items <bold> <italic> <center> <comment>
19 Net gain on sale of land <bold> RGB(193,216,47) <center> <large>
20 Extraordinary items after tax <bold> RGB(193,216,47) <center> <large>
21 Net Income (Profit) <bold> <night> <white> <center> <large>

View File

@@ -2,8 +2,8 @@
set -o errexit
echo "Creating release for version: $VERSION"
echo "Artifact name: ./build/${3}_${VERSION}.zip"
$HOME/bin/ghr -t ${ghoauth} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} ${VERSION} "./build/${3}_${4}.zip"
echo "Artifact name: ./dist/${3}_${VERSION}.zip"
$HOME/bin/ghr -t ${ghoauth} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} ${VERSION} "./dist/${3}_${4}.zip"
# Usage

25
scripts/verify-files.sh Normal file
View File

@@ -0,0 +1,25 @@
#!/bin/bash
# The build script has a known race-condition that sometimes causes it to not include all files
# in the built zip. This script verifies the that the zip contains the correct number of files.
set -o errexit
echo "Verifying built file count"
while read line; do
if [[ $line =~ ^\"name\": ]]; then
name=${line#*: \"}
name=${name%\"*}
fi
done < package.json
expected_file_count=$(($(find dist -type f | wc -l)-1))
zip_file_count=$(zipinfo dist/${name}_${VERSION}.zip | grep ^- | wc -l)
if [ "${expected_file_count}" -ne "${zip_file_count}" ]; then
# File count is incorrect
echo "Expected file count ${expected_file_count}, but was ${zip_file_count}"
exit 1
fi
echo "File count OK"
exit 0

View File

@@ -1,13 +0,0 @@
const path = require('path');
const packageJSON = require('./package.json');
const defaultBuildDestination = path.resolve("./build");
module.exports = {
buildDestination: process.env.BUILD_PATH || defaultBuildDestination,
mode: process.env.NODE_ENV || 'development',
name: packageJSON.name,
version: process.env.VERSION || 'local-dev',
url: process.env.BUILD_URL || defaultBuildDestination,
port: process.env.PORT || 8085
};

View File

@@ -3,9 +3,131 @@ import PropTypes from 'prop-types';
import { ApplyPreMask } from '../masking';
import { addSeparators } from '../utilities';
import Tooltip from '../tooltip/index.jsx';
class DataCell extends React.PureComponent {
constructor (props) {
super(props);
this.handleSelect = this.handleSelect.bind(this);
}
handleSelect () {
const { data: { meta: { dimensionCount } }, general: { allowFilteringByClick }, measurement, qlik } = this.props;
const hasSecondDimension = dimensionCount > 1;
if (!allowFilteringByClick) {
return;
}
qlik.backendApi.selectValues(0, [measurement.parents.dimension1.elementNumber], true);
if (hasSecondDimension) {
qlik.backendApi.selectValues(1, [measurement.parents.dimension2.elementNumber], true);
}
}
render () {
const {
data,
general,
measurement,
styleBuilder,
styling
} = this.props;
const isColumnPercentageBased = (/%/).test(measurement.format);
let formattedMeasurementValue = formatMeasurementValue(measurement, styling);
if (styleBuilder.hasComments()) {
formattedMeasurementValue = '.';
}
let textAlignment = 'Right';
const textAlignmentProp = styling.options.textAlignment;
if (textAlignmentProp) {
textAlignment = textAlignmentProp;
}
let cellStyle = {
fontFamily: styling.options.fontFamily,
...styleBuilder.getStyle(),
paddingLeft: '5px',
textAlign: textAlignment
};
const { semaphoreColors, semaphoreColors: { fieldsToApplyTo } } = styling;
const isValidSemaphoreValue = !styleBuilder.hasComments() && !isNaN(measurement.value);
const dimension1Row = measurement.parents.dimension1.elementNumber;
const isSpecifiedMetricField = fieldsToApplyTo.metricsSpecificFields.indexOf(dimension1Row) !== -1;
const shouldHaveSemaphoreColors = (fieldsToApplyTo.applyToMetric || isSpecifiedMetricField);
if (isValidSemaphoreValue && shouldHaveSemaphoreColors) {
const { backgroundColor, color } = getSemaphoreColors(measurement, semaphoreColors);
cellStyle = {
...styleBuilder.getStyle(),
backgroundColor,
color,
fontFamily: styling.options.fontFamily,
paddingLeft: '5px',
textAlign: textAlignment
};
}
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}`}
onClick={this.handleSelect}
style={cellStyle}
>
<Tooltip
tooltipText={formattedMeasurementValue}
>
{formattedMeasurementValue}
</Tooltip>
</td>
);
}
}
DataCell.propTypes = {
data: PropTypes.shape({
headers: PropTypes.shape({
measurements: PropTypes.array.isRequired
}).isRequired
}).isRequired,
general: PropTypes.shape({
cellSuffix: PropTypes.string.isRequired
}).isRequired,
measurement: PropTypes.shape({
format: PropTypes.string,
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,
styleBuilder: PropTypes.shape({
hasComments: PropTypes.func.isRequired
}).isRequired,
styling: PropTypes.shape({
symbolForNulls: PropTypes.any.isRequired
}).isRequired
};
export default DataCell;
function formatMeasurementValue (measurement, styling) {
// TODO: measurement.name is a horrible propertyname, it's actually the column header
const isColumnPercentageBased = measurement.parents.measurement.header.substring(0, 1) === '%';
const isColumnPercentageBased = (/%/).test(measurement.format);
let formattedMeasurementValue = '';
if (isColumnPercentageBased) {
if (isNaN(measurement.value)) {
@@ -53,124 +175,11 @@ function formatMeasurementValue (measurement, styling) {
}
function getSemaphoreColors (measurement, semaphoreColors) {
if (measurement < semaphoreColors.status.critical) {
if (measurement.value < semaphoreColors.status.critical) {
return semaphoreColors.statusColors.critical;
}
if (measurement < semaphoreColors.status.medium) {
if (measurement.value < semaphoreColors.status.medium) {
return semaphoreColors.statusColors.medium;
}
return semaphoreColors.statusColors.normal;
}
class DataCell extends React.PureComponent {
constructor (props) {
super(props);
this.handleSelect = this.handleSelect.bind(this);
}
handleSelect () {
const { data: { meta: { dimensionCount } }, general: { allowFilteringByClick }, measurement, qlik } = this.props;
const hasSecondDimension = dimensionCount > 1;
if (!allowFilteringByClick) {
return;
}
qlik.backendApi.selectValues(0, [measurement.parents.dimension1.elementNumber], true);
if (hasSecondDimension) {
qlik.backendApi.selectValues(1, [measurement.parents.dimension2.elementNumber], true);
}
}
render () {
const {
data,
general,
measurement,
styleBuilder,
styling
} = this.props;
const isColumnPercentageBased = measurement.name.substring(0, 1) === '%';
let formattedMeasurementValue = formatMeasurementValue(measurement, styling);
if (styleBuilder.hasComments()) {
formattedMeasurementValue = '.';
}
let textAlignment = 'Right';
const textAlignmentProp = styling.options.textAlignment;
if (textAlignmentProp) {
textAlignment = textAlignmentProp;
}
let cellStyle = {
fontFamily: styling.options.fontFamily,
...styleBuilder.getStyle(),
paddingLeft: '5px',
textAlign: textAlignment
};
const { semaphoreColors, semaphoreColors: { fieldsToApplyTo } } = styling;
const isValidSemaphoreValue = !styleBuilder.hasComments() && !isNaN(measurement.value);
const shouldHaveSemaphoreColors = (fieldsToApplyTo.applyToMetric || fieldsToApplyTo.specificFields.indexOf(measurement.parents.dimension1.header) !== -1);
if (isValidSemaphoreValue && shouldHaveSemaphoreColors) {
const { backgroundColor, color } = getSemaphoreColors(measurement, semaphoreColors);
cellStyle = {
...styleBuilder.getStyle(),
backgroundColor,
color,
fontFamily: styling.options.fontFamily,
paddingLeft: '5px',
textAlign: textAlignment
};
}
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}`}
onClick={this.handleSelect}
style={cellStyle}
>
<Tooltip
tooltipText={formattedMeasurementValue}
>
{formattedMeasurementValue}
</Tooltip>
</td>
);
}
}
DataCell.propTypes = {
data: PropTypes.shape({
headers: PropTypes.shape({
measurements: PropTypes.array.isRequired
}).isRequired
}).isRequired,
general: PropTypes.shape({
cellSuffix: PropTypes.string.isRequired
}).isRequired,
measurement: PropTypes.shape({
format: PropTypes.string,
name: PropTypes.string,
value: PropTypes.any
}).isRequired,
qlik: PropTypes.shape({
backendApi: PropTypes.shape({
selectValues: PropTypes.func.isRequired
}).isRequired
}).isRequired,
styleBuilder: PropTypes.shape({
hasComments: PropTypes.func.isRequired
}).isRequired,
styling: PropTypes.shape({
symbolForNulls: PropTypes.any.isRequired
}).isRequired
};
export default DataCell;

View File

@@ -1,6 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import HeaderPadding from './header-padding.jsx';
import Tooltip from '../tooltip/index.jsx';
class RowHeader extends React.PureComponent {
constructor (props) {
@@ -15,18 +16,25 @@ class RowHeader extends React.PureComponent {
}
render () {
const { entry, rowStyle, styleBuilder, styling } = this.props;
const { entry, rowStyle, styleBuilder, styling, qlik } = this.props;
const inEditState = qlik.inEditState();
return (
<td
className="fdim-cells"
onClick={this.handleSelect}
style={rowStyle}
>
<HeaderPadding
styleBuilder={styleBuilder}
styling={styling}
/>
{entry.displayValue}
<Tooltip
isTooltipActive={!inEditState}
tooltipText={entry.displayValue}
>
<HeaderPadding
styleBuilder={styleBuilder}
styling={styling}
/>
{entry.displayValue}
</Tooltip>
</td>
);
}
@@ -38,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
View 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
};
}

View File

@@ -1,68 +0,0 @@
const colorLibrary = {
type: 'items',
label: 'Primary Colors Library',
items: {
ColLibClean: {
ref: 'collibclean',
translation: 'Clean',
type: 'string',
defaultValue: '#ffffff'
},
ColLibSoft: {
ref: 'collibsoft',
translation: 'Soft',
type: 'string',
defaultValue: '#efefef'
},
ColLibDark: {
ref: 'collibdark',
translation: 'Dark',
type: 'string',
defaultValue: '#c4c4c4'
},
ColLibNight: {
ref: 'collibnight',
translation: 'Night',
type: 'string',
defaultValue: '#808080'
},
ColLibRed: {
ref: 'collibred',
translation: 'Red',
type: 'string',
defaultValue: '#d58b94'
},
ColLibOrange: {
ref: 'colliborange',
translation: 'Orange',
type: 'string',
defaultValue: '#fd6600'
},
ColLibViolete: {
ref: 'collibviolete',
translation: 'Violete',
type: 'string',
defaultValue: '#ccc0ff'
},
ColLibBlue: {
ref: 'collibblue',
translation: 'Blue',
type: 'string',
defaultValue: '#4575b4'
},
ColLibGreen: {
ref: 'collibgreen',
translation: 'Green',
type: 'string',
defaultValue: '#7bb51c'
},
ColLibCustom: {
ref: 'collibcustom',
label: 'Custom',
type: 'string',
defaultValue: '#ffcccc'
}
}
};
export default colorLibrary;

View File

@@ -24,102 +24,26 @@ const header = {
defaultValue: 2
},
headercolors: {
ref: 'HeaderColorSchema',
type: 'string',
component: 'dropdown',
component: 'color-picker',
defaultValue: {
index: 6,
color: '#4477aa'
},
label: 'Background Header Color',
options: [
{
value: 'Clean',
label: 'Clean'
},
{
value: 'Soft',
label: 'Soft'
},
{
value: 'Dark',
label: 'Dark'
},
{
value: 'Night',
label: 'Night'
},
{
value: 'Blue',
label: 'Blue'
},
{
value: 'Orange',
label: 'Orange'
},
{
value: 'Red',
label: 'Red'
},
{
value: 'Green',
label: 'Green'
},
{
value: 'Violete',
label: 'Violete'
},
{
value: 'Custom',
label: 'Custom'
}
],
defaultValue: 'Night'
ref: 'HeaderColorSchema',
type: 'object',
dualOutput: true
},
HeaderTextColor: {
ref: 'HeaderTextColorSchema',
type: 'string',
component: 'dropdown',
label: 'Text Header Color',
options: [
{
value: 'Black',
label: 'Black'
},
{
value: 'DimGray',
label: 'DimGray'
},
{
value: 'ForestGreen',
label: 'ForestGreen'
},
{
value: 'Gainsboro',
label: 'Gainsboro'
},
{
value: 'Indigo',
label: 'Indigo'
},
{
value: 'Navy',
label: 'Navy'
},
{
value: 'Purple',
label: 'Purple'
},
{
value: 'WhiteSmoke',
label: 'WhiteSmoke'
},
{
value: 'White',
label: 'White'
},
{
value: 'YellowGreen',
label: 'YellowGreen'
}
],
defaultValue: 'WhiteSmoke'
component: 'color-picker',
defaultValue: {
index: 1,
color: '#ffffff'
},
type: 'object',
dualOutput: true
},
HeaderFontSize: {
ref: 'lettersizeheader',
@@ -136,7 +60,7 @@ const header = {
label: 'Medium'
}
],
defaultValue: 2
defaultValue: 1
}
}
};

View File

@@ -1,10 +1,8 @@
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';
import colorLibrary from './color-library';
import pijamaColorLibrary from './pijama-color-library';
const definition = {
component: 'accordion',
@@ -22,13 +20,11 @@ const definition = {
},
settings: {
items: {
ColorLibrary: colorLibrary,
ConceptSemaphores: conceptSemaphores,
Formatted: formatted,
Formatted: tableFormat,
Header: header,
MetricSemaphores: metricSemaphores,
Pagination: pagination,
PijamaColorLibrary: pijamaColorLibrary
Pagination: pagination
},
uses: 'settings'
},

View File

@@ -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,8 +39,9 @@ const metricSemaphores = {
label: 'Critic Color Fill',
type: 'object',
component: 'color-picker',
dualOutput: true,
defaultValue: {
index: 7,
index: 8,
color: '#f93f17'
}
},
@@ -49,8 +50,9 @@ const metricSemaphores = {
label: 'Critic Color Text',
type: 'object',
component: 'color-picker',
dualOutput: true,
defaultValue: {
index: 10,
index: 11,
color: '#ffffff'
}
},
@@ -65,8 +67,9 @@ const metricSemaphores = {
label: 'Medium Color Fill',
type: 'object',
component: 'color-picker',
dualOutput: true,
defaultValue: {
index: 8,
index: 9,
color: '#ffcf02'
}
},
@@ -75,8 +78,9 @@ const metricSemaphores = {
label: 'Medium Color Text',
type: 'object',
component: 'color-picker',
dualOutput: true,
defaultValue: {
index: 11,
index: 12,
color: '#000000'
}
},
@@ -85,8 +89,9 @@ const metricSemaphores = {
label: 'Success Color Fill',
type: 'object',
component: 'color-picker',
dualOutput: true,
defaultValue: {
index: 9,
index: 10,
color: '#276e27'
}
},
@@ -95,8 +100,9 @@ const metricSemaphores = {
label: 'Success Color Text',
type: 'object',
component: 'color-picker',
dualOutput: true,
defaultValue: {
index: 10,
index: 11,
color: '#ffffff'
}
}

View File

@@ -1,68 +0,0 @@
const pijamaColorLibrary = {
type: 'items',
label: 'Pijama Colors Library',
items: {
ColLibCleanP: {
ref: 'collibcleanp',
translation: 'Clean',
type: 'string',
defaultValue: '#ffffff'
},
ColLibSoftP: {
ref: 'collibsoftp',
translation: 'Soft',
type: 'string',
defaultValue: '#ffffff'
},
ColLibDarkP: {
ref: 'collibdarkp',
translation: 'Dark',
type: 'string',
defaultValue: '#efefef'
},
ColLibNightP: {
ref: 'collibnightp',
translation: 'Night',
type: 'string',
defaultValue: '#c4c4c4'
},
ColLibRedP: {
ref: 'collibredp',
translation: 'Red',
type: 'string',
defaultValue: '#ffcccc'
},
ColLibOrangeP: {
ref: 'colliborangep',
translation: 'Orange',
type: 'string',
defaultValue: '#ffcc66'
},
ColLibVioleteP: {
ref: 'collibvioletep',
translation: 'Violete',
type: 'string',
defaultValue: '#e6e6ff'
},
ColLibBlueP: {
ref: 'collibbluep',
translation: 'Blue',
type: 'string',
defaultValue: '#b3d9ff'
},
ColLibGreenP: {
ref: 'collibgreenp',
translation: 'Green',
type: 'string',
defaultValue: '#98fb98'
},
ColLibCustomP: {
ref: 'collibcustomp',
label: 'Custom',
type: 'string',
defaultValue: '#ffffff'
}
}
};
export default pijamaColorLibrary;

View File

@@ -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,72 +20,29 @@ const formatted = {
label: 'Separator Columns',
defaultValue: false
},
CustomFileBool: {
ref: 'customfilebool',
type: 'boolean',
label: 'Include External File',
defaultValue: false
rowEvenBGColor: {
component: 'color-picker',
defaultValue: {
color: '#fff',
index: 1
},
label: 'Even row background color',
ref: 'rowEvenBGColor',
type: 'object',
dualOutput: true,
show: data => !hasDesignDimension(data)
},
CustomFile: {
ref: 'customfile',
label: 'Name of CSV file (; separated)',
type: 'string',
defaultValue: '',
show (data) {
return data.customfilebool;
}
},
colors: {
ref: 'ColorSchema',
type: 'string',
component: 'dropdown',
label: 'BackGround Style',
options: [
{
value: 'Clean',
label: 'Clean'
},
{
value: 'Soft',
label: 'Soft'
},
{
value: 'Dark',
label: 'Dark'
},
{
value: 'Night',
label: 'Night'
},
{
value: 'Blue',
label: 'Blue'
},
{
value: 'Orange',
label: 'Orange'
},
{
value: 'Red',
label: 'Red'
},
{
value: 'Green',
label: 'Green'
},
{
value: 'Violete',
label: 'Violete'
},
{
value: 'Custom',
label: 'Custom'
}
],
defaultValue: 'Clean',
show (data) {
return !data.customfilebool;
}
rowOddBGColor: {
component: 'color-picker',
defaultValue: {
color: '#b6d7ea',
index: 4
},
label: 'Odd row background color',
ref: 'rowOddBGColor',
type: 'object',
dualOutput: true,
show: data => !hasDesignDimension(data)
},
BodyTextColor: {
ref: 'BodyTextColorSchema',
@@ -129,9 +92,7 @@ const formatted = {
}
],
defaultValue: 'Black',
show (data) {
return !data.customfilebool;
}
show: data => !hasDesignDimension(data)
},
FontFamily: {
ref: 'FontFamily',
@@ -140,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',
@@ -260,4 +221,4 @@ const formatted = {
}
};
export default formatted;
export default tableFormat;

View File

@@ -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({

View File

@@ -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'
};

View File

@@ -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({

View File

@@ -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,23 +29,28 @@ 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: '70px',
fontSize: `${15 + fontSizeAdjustment}px`,
height: isMediumFontSize ? '100px' : '80px',
verticalAlign: 'middle'
};
return (
<th
className={`grid-cells2 ${general.cellSuffix}`}
className={`grid-cells2${general.cellSuffix}`}
style={style}
>
<span

View File

@@ -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
}
],

View File

@@ -1,31 +1,9 @@
import jQuery from 'jquery';
import { distinctArray } from './utilities';
// TODO: rename colors
function initializeColors ({ layout }) {
return {
vColLibBlue: layout.collibblue,
vColLibBlueP: layout.collibbluep,
vColLibClean: layout.collibclean,
vColLibCleanP: layout.collibcleanp,
vColLibCustom: layout.collibcustom,
vColLibCustomP: layout.collibcustomp,
vColLibDark: layout.collibdark,
vColLibDarkP: layout.collibdarkp,
vColLibGreen: layout.collibgreen,
vColLibGreenP: layout.collibgreenp,
vColLibNight: layout.collibnight,
vColLibNightP: layout.collibnightp,
vColLibOrange: layout.colliborange,
vColLibOrangeP: layout.colliborangep,
vColLibRed: layout.collibred,
vColLibRedP: layout.collibredp,
vColLibSoft: layout.collibsoft,
vColLibSoftP: layout.collibsoftp,
vColLibViolete: layout.collibviolete,
vColLibVioleteP: layout.collibvioletep
};
}
export const HEADER_FONT_SIZE = {
SMALL: -1,
MEDIUM: 1
};
function getAlignment (option) {
const alignmentOptions = {
@@ -39,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
};
@@ -129,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);
@@ -193,8 +172,7 @@ function generateDataSet (component, dimensionsInformation, measurementsInformat
};
}
async function initializeTransformed ({ $element, layout, component }) {
const colors = initializeColors({ layout });
function initializeTransformed ({ $element, component, cubes, layout }) {
const dimensionsInformation = component.backendApi.getDimensionInfos();
const measurementsInformation = component.backendApi.getMeasureInfos();
const dimensionCount = layout.qHyperCube.qDimensionInfo.length;
@@ -205,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 = {
@@ -264,22 +234,21 @@ async function initializeTransformed ({ $element, layout, component }) {
dimensionSelectionCounts: dimensionsInformation.map(dimensionInfo => dimensionInfo.qStateCounts.qSelected)
},
styling: {
colors,
customCSV: {
basic: customSchemaBasic,
count: customHeadersCount,
full: customSchemaFull
},
hasCustomFileStyle: layout.customfilebool,
hasCustomFileStyle: Boolean(cubes.design),
headerOptions: {
alignment: getAlignment(layout.HeaderAlign),
colorSchema: colors[`vColLib${layout.HeaderColorSchema}`],
colorSchema: layout.HeaderColorSchema.color,
fontSizeAdjustment: getFontSizeAdjustment(layout.lettersizeheader),
textColor: layout.HeaderTextColorSchema
textColor: layout.HeaderTextColorSchema.color
},
options: {
backgroundColor: colors[`vColLib${layout.ColorSchema}`],
backgroundColorOdd: colors[`vColLib${layout.ColorSchema}P`],
backgroundColor: layout.rowEvenBGColor,
backgroundColorOdd: layout.rowOddBGColor,
color: layout.BodyTextColorSchema,
fontFamily: layout.FontFamily,
fontSizeAdjustment: getFontSizeAdjustment(layout.lettersize),
@@ -299,11 +268,12 @@ async function initializeTransformed ({ $element, layout, component }) {
layout.conceptsemaphore7,
layout.conceptsemaphore9,
layout.conceptsemaphore10
]
],
metricsSpecificFields: layout.metricssemaphore.split(',').map(entry => Number(entry))
},
status: {
critical: layout.metricstatus1,
medium: layout.metricstatus2
critical: layout.metricsstatus1,
medium: layout.metricsstatus2
},
statusColors: {
critical: {
@@ -340,7 +310,6 @@ async function initializeTransformed ({ $element, layout, component }) {
});
}
return transformedProperties;
}

View File

@@ -24,38 +24,6 @@
z-index: 110;
}
.tooltip-wrapper {
min-width: 25px;
position: fixed;
padding: 5px;
padding-top: 15px;
background-color: #404040;
z-index: 100;
pointer-events: none;
border-radius: 5px;
height: 30px;
width: auto;
opacity: 0.9;
text-align: center;
transform: translate(-50%, -110%);
> p {
color: #fff;
}
}
.tooltip-wrapper::after {
content: "";
position: absolute;
bottom: -10px;
left: 50%;
border-width: 10px 10px 0;
border-style: solid;
border-color: #404040 transparent;
margin-left: -10px;
pointer-events: none;
}
.icon-xls {
text-align: left;
}
@@ -76,13 +44,20 @@
td,
th {
border: 1px solid #fff;
padding: 5px;
border-collapse: collapse;
padding: 5px !important; // prevent overwriting from single object
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: middle;
cursor: default;
> div {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-family: inherit;
}
}
.empty {
@@ -102,13 +77,14 @@
text-align: right;
}
/* This is for wrap text in headers */
// 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 {
@@ -133,11 +109,9 @@
width: 100%;
}
/* ***************** */
/* Medium column size */
/* ***************** */
// *****************
// Medium column size
// *****************
.grid-cells {
position: relative;
@@ -156,11 +130,9 @@
._cell(52px);
}
/* ***************** */
/* Small column size */
/* ***************** */
// *****************
// Small column size
// *****************
.grid-cells-s {
._cell(67px);
}
@@ -177,12 +149,9 @@
._cell(52px);
}
/* ***************** */
/* large column size */
/* ***************** */
// *****************
// Large column size
// *****************
.grid-cells-l {
._cell(82px);
}
@@ -199,9 +168,9 @@
._cell(66px);
}
/* END OF GRID CELLS */
// END OF GRID CELLS
/* First Column */
// First Column
.fdim-cells {
min-width: 230px !Important;
max-width: 230px !Important;
@@ -228,10 +197,6 @@
min-width: 522px;
}
.grid-cells::before {
content: "\00a0";
}
.grid {
height: 50px;
width: 350px;
@@ -275,6 +240,10 @@
}
}
.row-wrapper .fdim-cells {
padding-left: 12px;
}
.data-table {
height: 100%;
width: calc(100% - 243px);
@@ -297,10 +266,8 @@
// hide scrollbars
.kpi-table .header-wrapper,
.kpi-table .row-wrapper,
.data-table .header-wrapper,
.data-table .row-wrapper {
/* stylelint-disable-next-line property-no-unknown */
.data-table .header-wrapper {
// stylelint-disable-next-line property-no-unknown
scrollbar-width: none;
-ms-overflow-style: none; // IE 10+
-moz-overflow: -moz-scrollbars-none; // Firefox
@@ -309,4 +276,38 @@
display: none; // Safari and Chrome
}
}
.tooltip-wrapper {
min-width: 25px;
position: fixed;
padding: 5px;
padding-top: 8px;
background-color: #404040;
z-index: 100;
pointer-events: none;
border-radius: 5px;
height: 30px;
width: auto;
opacity: 0.9;
text-align: center;
transform: translate(-50%, -110%);
&::after {
content: "";
position: absolute;
bottom: -10px;
left: 50%;
border-width: 10px 10px 0;
border-style: solid;
border-color: #404040 transparent;
margin-left: -10px;
pointer-events: none;
}
> p {
color: #fff;
}
}
}
/* eslint-enable */

View File

@@ -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';

View File

@@ -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
});

View File

@@ -1,6 +1,5 @@
function StyleBuilder (styling) {
const {
colors,
customCSV,
options
} = styling;
@@ -12,9 +11,13 @@ function StyleBuilder (styling) {
let hasCustomFileStyle = false;
function applyStandardAttributes (rowNumber) {
const isEven = rowNumber % 2 === 0;
style.backgroundColor = isEven ? options.backgroundColor : options.backgroundColorOdd;
style.color = options.color;
const hasBackgroundColor = options.backgroundColor && options.backgroundColor.color;
const hasOddBackgroundColor = options.backgroundColorOdd && options.backgroundColorOdd.color;
if (hasBackgroundColor && hasOddBackgroundColor) {
const isEven = rowNumber % 2 === 0;
style.backgroundColor = isEven ? options.backgroundColor.color : options.backgroundColorOdd.color;
style.color = options.color;
}
style.fontSize = `${13 + options.fontSizeAdjustment}px`;
}
@@ -30,16 +33,7 @@ function StyleBuilder (styling) {
'<bold>': () => { style.fontWeight = 'bold'; },
'<italic>': () => { style.fontStyle = 'italic'; },
'<oblique>': () => { style.fontStyle = 'oblique'; },
// background and comment color
'<dark>': () => applyColor(colors.vColLibDark),
'<night>': () => applyColor(colors.vColLibNight),
'<soft>': () => applyColor(colors.vColLibSoft),
'<red>': () => applyColor(colors.vColLibRed),
'<orange>': () => applyColor(colors.vColLibOrange),
'<violete>': () => applyColor(colors.vColLibViolete),
'<blue>': () => applyColor(colors.vColLibBlue),
'<green>': () => applyColor(colors.vColLibGreen),
// font color TODO: this is a color just like the others, but it applies to text instead.. any way to make it less weird?
// font color
'<white>': () => { style.color = 'white'; },
// font size
'<large>': () => { style.fontSize = `${15 + options.fontSizeAdjustment}px`; },

View File

@@ -2,13 +2,15 @@ import React from 'react';
import PropTypes from 'prop-types';
const handleCalculateTooltipPosition = (event) => {
const tooltipClassName = 'tooltip-wrapper';
const tooltip = document.getElementsByClassName(tooltipClassName);
tooltip[0].style.left = event.clientX + 'px';
tooltip[0].style.top = event.clientY + 'px';
const tooltip = document.querySelector('.tooltip-wrapper');
if (!tooltip) {
return;
}
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 = {
@@ -17,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;
@@ -59,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;

File diff suppressed because one or more lines are too long

View File

@@ -1,10 +0,0 @@
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import jasmineEnzyme from 'jasmine-enzyme';
Enzyme.configure({ adapter: new Adapter() });
beforeEach(() => {
jasmineEnzyme();
});
export * from 'enzyme';

View File

@@ -1,9 +0,0 @@
import React from 'react';
import { mount } from 'test-utilities/enzyme-setup';
export function mountedComponent (Model, Component, props = {}) {
const component = mount((
<Component {...props} />
)).find(Component);
return new Model(component);
}

View File

@@ -1,8 +1,11 @@
const CopyWebpackPlugin = require('copy-webpack-plugin');
const StyleLintPlugin = require('stylelint-webpack-plugin');
const settings = require('./settings');
const packageJSON = require('./package.json');
const path = require('path');
console.log('Webpack mode:', settings.mode); // eslint-disable-line no-console
const DIST = path.resolve("./dist");
const MODE = process.env.NODE_ENV || 'development';
console.log('Webpack mode:', MODE); // eslint-disable-line no-console
const config = {
devtool: 'source-map',
@@ -13,13 +16,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']
// },
mode: MODE,
module: {
rules: [
{
@@ -59,22 +64,11 @@ const config = {
]
},
output: {
filename: `${settings.name}.js`,
filename: `${packageJSON.name}.js`,
libraryTarget: 'amd',
path: settings.buildDestination
path: DIST
},
plugins: [
new CopyWebpackPlugin([
`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'
], {}),
new StyleLintPlugin({
files: '**/*.less'
})