Compare commits

..

18 Commits
0.2.0 ... 0.3.0

Author SHA1 Message Date
Kristoffer Lind
2c6d978333 Merge pull request #4 from qlik-oss/feature/QPE-518
[QPE-518] Conversion and refactor
2019-01-30 16:10:47 +01:00
Kristoffer Lind
d669457ed9 fix the fix (messed up when removing else statement) 2019-01-30 15:16:21 +01:00
Kristoffer Lind
8ef5ef6450 rework baseCSS to reuse base object when possible 2019-01-30 15:01:09 +01:00
Kristoffer Lind
f6e629d9eb update paths to csv file and excel button 2019-01-30 12:43:54 +01:00
Kristoffer Lind
2322a5cdab fix 1-dim issue with headers 2019-01-30 11:07:27 +01:00
Kristoffer Lind
8a86fe4a30 refactor entrypoint 2019-01-30 08:44:45 +01:00
Kristoffer Lind
08cba41e18 init converted components in paint 2019-01-29 17:28:34 +01:00
Kristoffer Lind
9cfbb148fb fix eslint and review issues 2019-01-29 14:31:55 +01:00
Kristoffer Lind
4fd1cc1c3f Merge branch 'feature/QPE-555' into feature/QPE-518 2019-01-29 08:23:33 +01:00
Kristoffer Lind
2bf9259fdc some refactoring to get rid of duplicated code in row-lists 2019-01-25 18:43:02 +01:00
Kristoffer Lind
f0121b3a75 convert row-wrapper 2019-01-25 14:02:26 +01:00
Kristoffer Lind
5012db27a8 finalize component conversion 2019-01-24 09:07:36 +01:00
Kristoffer Lind
ec6713112a WIP: convert header-wrapper 2018-12-21 15:47:12 +01:00
Kristoffer Lind
86f009fd3f extract row wrapper 2018-12-21 14:24:43 +01:00
Kristoffer Lind
228053483a refactor: extract header-wrapper 2018-12-20 15:27:28 +01:00
Kristoffer Lind
76d835c15b fix messed up this references and some refactoring 2018-12-20 12:55:46 +01:00
Kristoffer Lind
22004e30c6 fix faulty css selector 2018-12-20 12:53:43 +01:00
Kristoffer Lind
d5662e2746 remove npm jquery dependency (jquery is supplied by qlik) 2018-12-20 12:52:58 +01:00
28 changed files with 2924 additions and 2463 deletions

View File

@@ -57,9 +57,82 @@ module.exports = {
"no-implied-eval": ["error"],
"no-debugger": ["warn"],
"no-unreachable": ["warn"],
"quotes": ["warn", "single", { "avoidEscape": true }]
"quotes": ["warn", "single", { "avoidEscape": true }],
"sort-imports": ["off"],
"max-lines-per-function": ["off"], // marks the entire functions, a bit too noisy
"complexity": ["warn"],
"camelcase": ["warn"],
"max-statements": ["off"], // marks the entire functions, a bit too noisy
"sort-vars": ["warn"],
"init-declarations": ["off"],
"capitalized-comments": ["off"],
"one-var": ["off"],
"no-var": ["warn"],
"no-plusplus": ["warn"],
"vars-on-top": ["off"],
"no-magic-numbers": ["off"], // useful, but also complains for reasonable checks with actual numbers
"new-cap": ["warn"],
"block-scoped-var": ["warn"],
"require-unicode-regexp": ["off"],
"no-negated-condition": ["warn"],
"operator-assignment": ["off"],
"no-extra-parens": ["off"],
"quote-props": ["off"],
"prefer-template": ["warn"],
"no-lonely-if": ["warn"],
"sort-keys": ["warn"],
"no-implicit-coercion": ["warn"],
"no-inline-comments": ["off"],
"spaced-comment": ["warn"],
"require-jsdoc": ["off"],
"func-style": ["off"],
"func-names": ["off"],
"id-length": ["warn"],
"prefer-arrow-callback": ["warn"],
"dot-location": ["off"],
"line-comment-position": ["off"],
"no-warning-comments": ["warn"],
"multiline-comment-style": ["off"],
"consistent-return": ["warn"],
"no-else-return": ["warn"],
"array-bracket-newline": ["warn"],
"array-element-newline": ["warn"],
"object-shorthand": ["warn"],
"eqeqeq": ["warn"],
"no-empty-function": ["off"],
"function-paren-newline": ["warn"],
"no-invalid-this": ["warn"],
"newline-per-chained-call": ["warn"],
"no-unused-expressions": ["warn"],
"strict": ["warn"],
"no-ternary": ["off"],
"multiline-ternary": ["off"],
"no-param-reassign": ["warn"],
"prefer-destructuring": ["warn"],
"arrow-parens": ["off"],
"no-array-constructor": ["warn"],
"default-case": ["warn"],
"no-alert": ["warn"],
"max-params": ["warn"],
"brace-style": ["warn", "1tbs", { "allowSingleLine": true }],
"prefer-const": ["warn"],
// plugin:react
"react/jsx-indent": ["warn", 2],
"react/jsx-indent-props": ["warn", 2],
"react/forbid-prop-types": ["warn"],
"react/no-array-index-key": ["warn"],
"react/jsx-sort-props": ["warn"],
"react/require-default-props": ["warn"],
"react/sort-prop-types": ["warn"],
"react/jsx-max-props-per-line": ["warn"],
"react/jsx-no-literals": ["off"],
"react/jsx-max-depth": ["off"], // rule throws exception in single-dimension-measure
"react/jsx-filename-extension": ["warn"],
"react/prefer-stateless-function": ["warn"]
},
extends: [
"eslint:recommended"
"eslint:all",
"plugin:react/all"
]
}

1
.gitattributes vendored
View File

@@ -22,6 +22,7 @@
*.scss text eol=lf
*.html text eol=lf
*.js text eol=lf
*.jsx text eol=lf
*.json text eol=lf
*.md text eol=lf
*.sh text eol=lf

176
package-lock.json generated
View File

@@ -67,6 +67,29 @@
"@babel/types": "^7.0.0"
}
},
"@babel/helper-builder-react-jsx": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.3.0.tgz",
"integrity": "sha512-MjA9KgwCuPEkQd9ncSXvSyJ5y+j2sICHyrI0M3L+6fnS4wMSNDc1ARXsbTfbb2cXHn17VisSnU/sHFTCxVxSMw==",
"dev": true,
"requires": {
"@babel/types": "^7.3.0",
"esutils": "^2.0.0"
},
"dependencies": {
"@babel/types": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.0.tgz",
"integrity": "sha512-QkFPw68QqWU1/RVPyBe8SO7lXbPfjtqAxRYQKpFpaB8yMq7X2qAqfwK5LKoQufEkSmO5NQ70O6Kc3Afk03RwXw==",
"dev": true,
"requires": {
"esutils": "^2.0.2",
"lodash": "^4.17.10",
"to-fast-properties": "^2.0.0"
}
}
}
},
"@babel/helper-call-delegate": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.1.0.tgz",
@@ -338,6 +361,15 @@
"@babel/helper-plugin-utils": "^7.0.0"
}
},
"@babel/plugin-syntax-jsx": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.2.0.tgz",
"integrity": "sha512-VyN4QANJkRW6lDBmENzRszvZf3/4AXaj9YR7GwrWeeN9tEBPuXbmDYVU9bYBN0D70zCWVwUy0HWq2553VCb6Hw==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
}
},
"@babel/plugin-syntax-object-rest-spread": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz",
@@ -366,9 +398,9 @@
}
},
"@babel/plugin-transform-async-to-generator": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.2.0.tgz",
"integrity": "sha512-CEHzg4g5UraReozI9D4fblBYABs7IM6UerAVG7EJVrTLC5keh00aEuLUT+O40+mJCEzaXkYfTCUKIyeDfMOFFQ==",
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.1.0.tgz",
"integrity": "sha512-rNmcmoQ78IrvNCIt/R9U+cixUHeYAzgusTFgIAv+wQb9HJU4szhpDD6e5GCACmj/JP5KxuCwM96bX3L9v4ZN/g==",
"dev": true,
"requires": {
"@babel/helper-module-imports": "^7.0.0",
@@ -558,6 +590,46 @@
"@babel/helper-plugin-utils": "^7.0.0"
}
},
"@babel/plugin-transform-react-display-name": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.2.0.tgz",
"integrity": "sha512-Htf/tPa5haZvRMiNSQSFifK12gtr/8vwfr+A9y69uF0QcU77AVu4K7MiHEkTxF7lQoHOL0F9ErqgfNEAKgXj7A==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
}
},
"@babel/plugin-transform-react-jsx": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.3.0.tgz",
"integrity": "sha512-a/+aRb7R06WcKvQLOu4/TpjKOdvVEKRLWFpKcNuHhiREPgGRB4TQJxq07+EZLS8LFVYpfq1a5lDUnuMdcCpBKg==",
"dev": true,
"requires": {
"@babel/helper-builder-react-jsx": "^7.3.0",
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/plugin-syntax-jsx": "^7.2.0"
}
},
"@babel/plugin-transform-react-jsx-self": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.2.0.tgz",
"integrity": "sha512-v6S5L/myicZEy+jr6ielB0OR8h+EH/1QFx/YJ7c7Ua+7lqsjj/vW6fD5FR9hB/6y7mGbfT4vAURn3xqBxsUcdg==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/plugin-syntax-jsx": "^7.2.0"
}
},
"@babel/plugin-transform-react-jsx-source": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.2.0.tgz",
"integrity": "sha512-A32OkKTp4i5U6aE88GwwcuV4HAprUgHcTq0sSafLxjr6AW0QahrCRCjxogkbbcdtpbXkuTOlgpjophCxb6sh5g==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/plugin-syntax-jsx": "^7.2.0"
}
},
"@babel/plugin-transform-regenerator": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.0.0.tgz",
@@ -684,6 +756,19 @@
"semver": "^5.3.0"
}
},
"@babel/preset-react": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.0.0.tgz",
"integrity": "sha512-oayxyPS4Zj+hF6Et11BwuBkmpgT/zMxyuZgFrMeZID6Hdh3dGlk4sHCAhdBCpuCKW2ppBfl2uCCetlrUIJRY3w==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/plugin-transform-react-display-name": "^7.0.0",
"@babel/plugin-transform-react-jsx": "^7.0.0",
"@babel/plugin-transform-react-jsx-self": "^7.0.0",
"@babel/plugin-transform-react-jsx-source": "^7.0.0"
}
},
"@babel/template": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.1.2.tgz",
@@ -1156,6 +1241,16 @@
"integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==",
"dev": true
},
"array-includes": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz",
"integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=",
"dev": true,
"requires": {
"define-properties": "^1.1.2",
"es-abstract": "^1.7.0"
}
},
"array-initial": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz",
@@ -3583,6 +3678,19 @@
"rimraf": "^2.6.1"
}
},
"eslint-plugin-react": {
"version": "7.11.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.11.1.tgz",
"integrity": "sha512-cVVyMadRyW7qsIUh3FHp3u6QHNhOgVrLQYdQEB1bPWBsgbNCHdFAeNMquBMCcZJu59eNthX053L70l7gRt4SCw==",
"dev": true,
"requires": {
"array-includes": "^3.0.3",
"doctrine": "^2.1.0",
"has": "^1.0.3",
"jsx-ast-utils": "^2.0.1",
"prop-types": "^15.6.2"
}
},
"eslint-scope": {
"version": "3.7.1",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz",
@@ -6323,12 +6431,6 @@
"integrity": "sha512-pa9tbBWgU0EE4SWgc85T4sa886ufuQdsgruQANhECYjwqgV4z7Vw/499aCaP8ZH79JDS4vhm8doDG9HO4+e4sA==",
"dev": true
},
"jquery": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz",
"integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg==",
"dev": true
},
"js-base64": {
"version": "2.4.9",
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.9.tgz",
@@ -6357,8 +6459,7 @@
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"dev": true
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
},
"js-yaml": {
"version": "3.12.0",
@@ -6454,6 +6555,15 @@
"verror": "1.10.0"
}
},
"jsx-ast-utils": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz",
"integrity": "sha1-6AGxs5mF4g//yHtA43SAgOLcrH8=",
"dev": true,
"requires": {
"array-includes": "^3.0.3"
}
},
"just-debounce": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.0.0.tgz",
@@ -6989,7 +7099,6 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"dev": true,
"requires": {
"js-tokens": "^3.0.0 || ^4.0.0"
}
@@ -7630,8 +7739,7 @@
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
"dev": true
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
},
"object-component": {
"version": "0.0.3",
@@ -8534,6 +8642,15 @@
"integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=",
"dev": true
},
"prop-types": {
"version": "15.6.2",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz",
"integrity": "sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==",
"requires": {
"loose-envify": "^1.3.1",
"object-assign": "^4.1.1"
}
},
"proto-list": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
@@ -8719,6 +8836,28 @@
}
}
},
"react": {
"version": "16.7.0",
"resolved": "https://registry.npmjs.org/react/-/react-16.7.0.tgz",
"integrity": "sha512-StCz3QY8lxTb5cl2HJxjwLFOXPIFQp+p+hxQfc8WE0QiLfCtIlKj8/+5tjjKm8uSTlAW+fCPaavGFS06V9Ar3A==",
"requires": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
"prop-types": "^15.6.2",
"scheduler": "^0.12.0"
}
},
"react-dom": {
"version": "16.7.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.7.0.tgz",
"integrity": "sha512-D0Ufv1ExCAmF38P2Uh1lwpminZFRXEINJe53zRAbm4KPwSyd6DY/uDoS0Blj9jvPpn1+wivKpZYc8aAAN/nAkg==",
"requires": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
"prop-types": "^15.6.2",
"scheduler": "^0.12.0"
}
},
"read-pkg": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
@@ -9268,6 +9407,15 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true
},
"scheduler": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.12.0.tgz",
"integrity": "sha512-t7MBR28Akcp4Jm+QoR63XgAi9YgCUmgvDHqf5otgAj4QvdoBE4ImCX0ffehefePPG+aitiYHp0g/mW6s4Tp+dw==",
"requires": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1"
}
},
"schema-utils": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",

View File

@@ -16,8 +16,10 @@
},
"devDependencies": {
"@babel/core": "7.1.2",
"@babel/plugin-transform-async-to-generator": "7.1.0",
"@babel/polyfill": "7.0.0",
"@babel/preset-env": "7.1.0",
"@babel/preset-react": "7.0.0",
"babel-eslint": "10.0.1",
"babel-loader": "8.0.4",
"copy-webpack-plugin": "4.5.3",
@@ -25,11 +27,11 @@
"del": "2.0.2",
"eslint": "5.7.0",
"eslint-loader": "2.1.1",
"eslint-plugin-react": "7.11.1",
"gulp": "4.0.0",
"gulp-json-editor": "2.4.3",
"gulp-zip": "3.0.2",
"jasmine-core": "3.2.1",
"jquery": "3.3.1",
"karma": "3.0.0",
"karma-chrome-launcher": "2.2.0",
"karma-jasmine": "1.1.2",
@@ -44,5 +46,10 @@
"webpack": "4.20.2",
"webpack-cli": "3.1.2",
"webpack-dev-server": "3.1.10"
},
"dependencies": {
"prop-types": "15.6.2",
"react": "16.7.0",
"react-dom": "16.7.0"
}
}

View File

@@ -1,294 +0,0 @@
.qv-object-PLSmartPivot div.qv-object-content-container {
overflow-x:scroll;
overflow-y:hidden;
z-index:110
}
.qv-object-PLSmartPivot icon-xls {
text-align:left
}
.qv-object-PLSmartPivot button {
width: 100%;
}
.qv-object-PLSmartPivot table{
border-collapse:collapse;
border-spacing:0;
width:auto;
border-left:1px solid #d3d3d3;
border-right:1px solid #d3d3d3;
border-top:1px solid #d3d3d3
}
.qv-object-PLSmartPivot td, th{
border: 1px solid #ffffff;
padding:5px;
border-collapse: collapse;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: middle;
cursor: default;
}
.qv-object-PLSmartPivot .empty{
width:3%;
background:#ffffff;
min-width:4px !important;
max-width:4px !important;
/*border-right:1px solid white;
box-shadow:4px 2px 8px #e1e1e1
border-bottom:0;
border-top:0;
border-left:1px solid #d3d3d3;
border-right:1px solid #d3d3d3;
border-top:#fff 1px solid;
border-bottom:#fff 1px solid*/
}
.qv-object-PLSmartPivot th.main-kpi{
text-align:center;
vertical-align:middle;
border-bottom:1px solid #d3d3d3
}
.qv-object-PLSmartPivot .numeric{
text-align:right
}
.grid{
height:50px;
width:350px
}
.header-wrapper{
position:absolute;
top:0;
z-index:1
}
/*popups for headers*/
.tooltip
{
position: fixed!important;
color: RGB(70,70,70);
background-color: RGB(245,239,207);
text-align: center;
border: groove;
}
/*end popups*/
.row-wrapper{
position:absolute;
top:97px;
height:100%!Important;
overflow-x:hidden;
overflow-y:scroll;
padding:0;
margin-top:0;
}
/*This is for wrap text in headers*/
.qv-object-PLSmartPivot .wrapclass25{
width:100%;
height:25px;
white-space: pre-line;
overflow: hidden;
display:block;
}
.qv-object-PLSmartPivot .wrapclass45{
width:100%;
height:45px;
white-space: pre-line;
overflow: hidden;
display:block;
}
.qv-object-PLSmartPivot .wrapclass70{
width:100%;
height:70px;
white-space: pre-line;
overflow: hidden;
display:inline-block;
vertical-align: middle;
line-height: 20px;
}
.qv-object-PLSmartPivot .wrapclassEmpty{
width:100%;
}
/*******************/
/* Medium column size*/
/*******************/
/*body*/
.qv-object-PLSmartPivot .grid-cells{
min-width:70px!Important;
max-width:70px!Important;
cursor: pointer;
/*padding:5px 10px;
margin:0;*/
}
/*header*/
.qv-object-PLSmartPivot .grid-cells2{
min-width:69px!Important;
max-width:69px!Important;
cursor: pointer;
/*padding:5px 10px;
margin:0;*/
}
/*body*/
.qv-object-PLSmartPivot .grid-cells-small{
min-width:52px!Important;
max-width:52px!Important;
cursor: pointer;
/*padding:5px 10px;
margin:0;*/
}
/*header*/
.qv-object-PLSmartPivot .grid-cells2-small{
min-width:51px!Important;
max-width:51px!Important;
cursor: pointer;
/*padding:5px 10px;
margin:0;*/
}
/*******************/
/* Small column size*/
/*******************/
/*body*/
.qv-object-PLSmartPivot .grid-cells-s{
min-width:67px!Important;
max-width:67px!Important;
cursor: pointer;
/*padding:5px 10px;
margin:0;*/
}
/*header*/
.qv-object-PLSmartPivot .grid-cells2-s{
min-width:66px!Important;
max-width:66px!Important;
cursor: pointer;
/*padding:5px 10px;
margin:0;*/
}
/*body*/
.qv-object-PLSmartPivot .grid-cells-small-s{
min-width:52px!Important;
max-width:52px!Important;
cursor: pointer;
/*padding:5px 10px;
margin:0;*/
}
/*header*/
.qv-object-PLSmartPivot .grid-cells2-small-s{
min-width:51px!Important;
max-width:51px!Important;
cursor: pointer;
/*padding:5px 10px;
margin:0;*/
}
/*******************/
/* large column size*/
/*******************/
/*body*/
.qv-object-PLSmartPivot .grid-cells-l{
min-width:82px!Important;
max-width:82px!Important;
cursor: pointer;
/*padding:5px 10px;
margin:0;*/
}
/*header*/
.qv-object-PLSmartPivot .grid-cells2-l{
min-width:81px!Important;
max-width:81px!Important;
cursor: pointer;
/*padding:5px 10px;
margin:0;*/
}
/*body*/
.qv-object-PLSmartPivot .grid-cells-small-l{
min-width:66px!Important;
max-width:66px!Important;
cursor: pointer;
/*padding:5px 10px;
margin:0;*/
}
/*header*/
.qv-object-PLSmartPivot .grid-cells2-small-l{
min-width:65px!Important;
max-width:65px!Important;
cursor: pointer;
/*padding:5px 10px;
margin:0;*/
}
/*END OF GRID CELLS*/
/*First Column*/
.qv-object-PLSmartPivot .fdim-cells{
min-width:230px!Important;
max-width:230px!Important;
cursor: pointer;
background-color:white;
/*padding:0 20px*/
}
.qv-object-PLSmartPivot .fdim-cells:hover {
/*cursor: default;*/
background-color:#808080 !important;
color:#ffffff;
}
.qv-object-PLSmartPivot tbody tr:hover {
cursor: default;
background-color:#808080 !important;
color:#ffffff;
}
.qv-object-PLSmartPivot .grid-cells-header{
/*padding:15px 10px*/
padding:0px
}
.qv-object-PLSmartPivot .grid-cells-title{
min-width:522px
}
/*estos dos hcen referencia a la primera columna*/
.kpi-table .fdim-cells{
/*padding:5px 10px*/
}
.data-table .fdim-cells{
display:none
}
.kpi-table{
width:240px !important;
overflow:hidden !important;
display:table;
height:100%;
z-index:100;
/*background:white;*/
left:258px;
margin:0;
padding:0;
z-index:999;
position:absolute;
top:0;
left:0;
border-right:1px solid white;
box-shadow:4px 2px 8px #e1e1e1
}
.kpi-table .row-wrapper{
overflow:hidden
}
.data-table{
width:272px !important;
float:left;
display:table;
height:100%;
z-index:90;
position:absolute;
margin-left:253px;
-ms-overflow-style:none
}

View File

@@ -0,0 +1,68 @@
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

@@ -0,0 +1,96 @@
const conceptSemaphores = {
items: {
AllConcepts: {
component: 'switch',
defaultValue: true,
label: 'All concepts affected',
options: [
{
label: 'On',
value: true
},
{
label: 'Off',
value: false
}
],
ref: 'allsemaphores',
type: 'boolean'
},
ConceptsAffected1: {
defaultValue: '',
ref: 'conceptsemaphore1',
show: data => !data.allsemaphores,
translation: 'Concept 1',
type: 'string'
},
ConceptsAffected2: {
defaultValue: '',
ref: 'conceptsemaphore2',
show: data => !data.allsemaphores,
translation: 'Concept 2',
type: 'string'
},
ConceptsAffected3: {
defaultValue: '',
ref: 'conceptsemaphore3',
show: data => !data.allsemaphores,
translation: 'Concept 3',
type: 'string'
},
ConceptsAffected4: {
defaultValue: '',
ref: 'conceptsemaphore4',
show: data => !data.allsemaphores,
translation: 'Concept 4',
type: 'string'
},
ConceptsAffected5: {
defaultValue: '',
ref: 'conceptsemaphore5',
show: data => !data.allsemaphores,
translation: 'Concept 5',
type: 'string'
},
ConceptsAffected6: {
defaultValue: '',
ref: 'conceptsemaphore6',
show: data => !data.allsemaphores,
translation: 'Concept 6',
type: 'string'
},
ConceptsAffected7: {
defaultValue: '',
ref: 'conceptsemaphore7',
show: data => !data.allsemaphores,
translation: 'Concept 7',
type: 'string'
},
ConceptsAffected8: {
defaultValue: '',
ref: 'conceptsemaphore8',
show: data => !data.allsemaphores,
translation: 'Concept 8',
type: 'string'
},
ConceptsAffected9: {
defaultValue: '',
ref: 'conceptsemaphore9',
show: data => !data.allsemaphores,
translation: 'Concept 9',
type: 'string'
},
// eslint-disable-next-line sort-keys
ConceptsAffected10: {
defaultValue: '',
ref: 'conceptsemaphore10',
show: data => !data.allsemaphores,
translation: 'Concept 10',
type: 'string'
}
},
label: 'Concept Semaphores',
type: 'items'
};
export default conceptSemaphores;

239
src/definition/formatted.js Normal file
View File

@@ -0,0 +1,239 @@
const formatted = {
type: 'items',
label: 'Table Format',
items: {
IndentBool: {
ref: 'indentbool',
type: 'boolean',
label: 'Indent',
defaultValue: true
},
SeparatorColumns: {
ref: 'separatorcols',
type: 'boolean',
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;
}
},
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 == false;
}
},
BodyTextColor: {
ref: 'BodyTextColorSchema',
type: 'string',
component: 'dropdown',
label: 'Text Body 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: 'Black',
show (data) {
return data.customfilebool == false;
}
},
FontFamily: {
ref: 'FontFamily',
type: 'string',
component: 'dropdown',
label: 'FontFamily',
options: [
{
value: 'Arial',
label: 'Arial'
},
{
value: 'Calibri',
label: 'Calibri'
},
{
value: 'Comic Sans MS',
label: 'Comic Sans MS'
},
{
value: 'MS Sans Serif',
label: 'MS Sans Serif'
},
{
value: 'Tahoma',
label: 'Tahoma'
},
{
value: 'Verdana',
label: 'Verdana'
}
],
defaultValue: 'Calibri'
},
DataFontSize: {
ref: 'lettersize',
translation: 'Font Size',
type: 'number',
component: 'buttongroup',
options: [
{
value: 1,
label: 'Small'
},
{
value: 2,
label: 'Medium'
}
],
defaultValue: 2
},
ColumnWidthSlider: {
type: 'number',
component: 'slider',
label: 'Column Width',
ref: 'columnwidthslider',
min: 1,
max: 3,
step: 1,
defaultValue: 2
},
SymbolForNulls: {
ref: 'symbolfornulls',
label: 'Symbol for Nulls',
type: 'string',
defaultValue: ' '
},
AllowExportXLS: {
ref: 'allowexportxls',
type: 'boolean',
component: 'switch',
label: 'Allow export to Excel',
options: [
{
value: true,
label: 'On'
},
{
value: false,
label: 'Off'
}
],
defaultValue: true
},
FilterOnCellClick: {
ref: 'filteroncellclick',
type: 'boolean',
component: 'switch',
label: 'Filter data when cell clicked',
options: [
{
value: true,
label: 'On'
},
{
value: false,
label: 'Off'
}
],
defaultValue: true
}
}
};
export default formatted;

144
src/definition/header.js Normal file
View File

@@ -0,0 +1,144 @@
const header = {
type: 'items',
label: 'Header Format',
items: {
Align: {
ref: 'HeaderAlign',
translation: 'Header Alignment',
type: 'number',
component: 'buttongroup',
options: [
{
value: 1,
label: 'Left'
},
{
value: 2,
label: 'Center'
},
{
value: 3,
label: 'Right'
}
],
defaultValue: 2
},
headercolors: {
ref: 'HeaderColorSchema',
type: 'string',
component: 'dropdown',
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'
},
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'
},
HeaderFontSize: {
ref: 'lettersizeheader',
translation: 'Font Size',
type: 'number',
component: 'buttongroup',
options: [
{
value: 1,
label: 'Small'
},
{
value: 2,
label: 'Medium'
}
],
defaultValue: 2
}
}
};
export default header;

41
src/definition/index.js Normal file
View File

@@ -0,0 +1,41 @@
import pagination from './pagination';
import header from './header';
import formatted from './formatted';
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',
items: {
dimensions: {
max: 2,
min: 1,
uses: 'dimensions'
},
measures: {
max: 9,
min: 1,
uses: 'measures'
},
settings: {
items: {
ColorLibrary: colorLibrary,
ConceptSemaphores: conceptSemaphores,
Formatted: formatted,
Header: header,
MetricSemaphores: metricSemaphores,
Pagination: pagination,
PijamaColorLibrary: pijamaColorLibrary
},
uses: 'settings'
},
sorting: {
uses: 'sorting'
}
},
type: 'items'
};
export default definition;

View File

@@ -0,0 +1,106 @@
const metricSemaphores = {
type: 'items',
label: 'Metric Semaphores',
items: {
AllMetrics: {
ref: 'allmetrics',
type: 'boolean',
component: 'switch',
label: 'All metrics affected',
options: [
{
value: true,
label: 'On'
},
{
value: false,
label: 'Off'
}
],
defaultValue: false
},
MetricsAffected: {
ref: 'metricssemaphore',
translation: 'Metrics affected (1,2,4,...)',
type: 'string',
defaultValue: '0',
show (data) {
return data.allmetrics == false;
}
},
MetricStatus1: {
ref: 'metricsstatus1',
translation: 'Critic is less than',
type: 'number',
defaultValue: -0.1
},
ColorStatus1: {
ref: 'colorstatus1',
label: 'Critic Color Fill',
type: 'object',
component: 'color-picker',
defaultValue: {
index: 7,
color: '#f93f17'
}
},
ColorStatus1Text: {
ref: 'colorstatus1text',
label: 'Critic Color Text',
type: 'object',
component: 'color-picker',
defaultValue: {
index: 10,
color: '#ffffff'
}
},
MetricStatus2: {
ref: 'metricsstatus2',
translation: 'Medium is less than',
type: 'number',
defaultValue: 0
},
ColorStatus2: {
ref: 'colorstatus2',
label: 'Medium Color Fill',
type: 'object',
component: 'color-picker',
defaultValue: {
index: 8,
color: '#ffcf02'
}
},
ColorStatus2Text: {
ref: 'colorstatus2text',
label: 'Medium Color Text',
type: 'object',
component: 'color-picker',
defaultValue: {
index: 11,
color: '#000000'
}
},
ColorStatus3: {
ref: 'colorstatus3',
label: 'Success Color Fill',
type: 'object',
component: 'color-picker',
defaultValue: {
index: 9,
color: '#276e27'
}
},
ColorStatus3Text: {
ref: 'colorstatus3text',
label: 'Success Color Text',
type: 'object',
component: 'color-picker',
defaultValue: {
index: 10,
color: '#ffffff'
}
}
}
};
export default metricSemaphores;

View File

@@ -0,0 +1,63 @@
const pagination = {
type: 'items',
label: 'Pagination',
items: {
MaxPaginationLoops: {
ref: 'maxloops',
type: 'number',
component: 'dropdown',
label: 'Max Pagination Loops',
options: [
{
value: 1,
label: '10k cells'
},
{
value: 2,
label: '20k cells'
},
{
value: 3,
label: '30k cells'
},
{
value: 4,
label: '40k cells'
},
{
value: 5,
label: '50k cells'
},
{
value: 6,
label: '60k cells'
},
{
value: 7,
label: '70k cells'
},
{
value: 8,
label: '80k cells'
},
{
value: 9,
label: '90k cells'
},
{
value: 10,
label: '100k cells'
}
],
defaultValue: 2
},
ErrorMessage: {
ref: 'errormessage',
label: 'Default error message',
type: 'string',
defaultValue: 'Ups! It seems you asked for too many data. Please filter more to see the whole picture.'
}
}
};
export default pagination;

View File

@@ -0,0 +1,68 @@
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

@@ -0,0 +1,222 @@
import React from 'react';
import PropTypes from 'prop-types';
import { ApplyPreMask } from './masking';
import { addSeparators } from './utilities';
class ElseDimensionMeasures extends React.PureComponent {
render () {
const {
vFontFamily,
vSeparatorCols,
measure_count,
sufixCells,
vSymbolForNulls,
vLetterSize,
vColorMetric1,
vColorMetric1Text,
vColorMetric2,
vColorMetric2Text,
vColorMetric3,
vColorMetric3Text,
vAllSemaphores,
ConceptMatrixPivot,
ConceptsAffectedMatrix,
vAllMetrics,
MetricsAffectedMatrix,
vCritic,
vMMedium,
vNumMeasures,
vNumMeasures2,
MeasuresFormat,
rowNumber,
columnText,
styleBuilder
} = this.props;
// modified in here
let columnNumber,
vMaskNum,
vColorSemaphore,
vColorSemaphoreText,
vDivide;
const measurementCells = [];
var nMeasure7 = 0;
var nMeasure72 = -1;
var nMeasure72Semaphore = 0;
for (var nMeasures22 = 1; nMeasures22 <= vNumMeasures2; nMeasures22++) {
nMeasure7++;
nMeasure72++;
if (columnText.substring(0, 1) === '%') {
columnNumber = ApplyPreMask('0,00%', ConceptMatrixPivot[rowNumber][nMeasures22]);
var vSpecialF = '0,00%';
} else {
switch (MeasuresFormat[nMeasure72].substr(MeasuresFormat[nMeasure72].length - 1)) {
case 'k':
vDivide = 1000;
break;
case 'K':
vDivide = 1000;
break;
case 'm':
vDivide = 1000000;
break;
case 'M':
vDivide = 1000000;
break;
default:
vDivide = 1;
break;
}
var vSpecialF = MeasuresFormat[nMeasure72].replace(/k|K|m|M/gi, '');
if (!isNaN(ConceptMatrixPivot[rowNumber][nMeasures22])) {
vMaskNum = ConceptMatrixPivot[rowNumber][nMeasures22];
if (vSpecialF.substring(vSpecialF.length - 1) === '%') {
vMaskNum = vMaskNum * 100;
}
switch (vSpecialF) {
case '#.##0':
columnNumber = addSeparators((vMaskNum / vDivide), '.', ',', 0);
break;
case '#,##0':
columnNumber = addSeparators((vMaskNum / vDivide), ',', '.', 0);
break;
default:
columnNumber = ApplyPreMask(vSpecialF, (vMaskNum / vDivide));
break;
}
} else {
columnNumber = vSymbolForNulls;
}
}
if (vSeparatorCols && nMeasure7 === (measure_count + 1)) {
const seperatorStyle = {
color: 'white',
fontFamily: vFontFamily,
fontSize: (12 + vLetterSize) + 'px'
};
const seperatorElement = (
<th key={`${nMeasures22}-header`} className="empty" style={seperatorStyle}>
*
</th>
);
measurementCells.push(seperatorElement);
nMeasure7 = 1;
}
if (nMeasure72 === (measure_count - 1)) {
nMeasure72 = -1;
nMeasure72Semaphore = measure_count;
} else {
nMeasure72Semaphore = nMeasure72 + 1;
}
// apply the semaphores where needed
if (styleBuilder.hasComments()) {
columnNumber = '.';
}
let cellElement;
if ((vAllSemaphores || ConceptsAffectedMatrix.indexOf(columnText) >= 0) && (vAllMetrics || MetricsAffectedMatrix.indexOf(nMeasure72Semaphore) >= 0) && !isNaN(ConceptMatrixPivot[rowNumber][nMeasures22]) && !styleBuilder.hasComments()) {
if (ConceptMatrixPivot[rowNumber][nMeasures22] < vCritic) {
vColorSemaphore = vColorMetric1;
vColorSemaphoreText = vColorMetric1Text;
} else {
if (ConceptMatrixPivot[rowNumber][nMeasures22] < vMMedium) {
vColorSemaphore = vColorMetric2;
vColorSemaphoreText = vColorMetric2Text;
} else {
vColorSemaphore = vColorMetric3;
vColorSemaphoreText = vColorMetric3Text;
}
}
const cellStyle = {
fontFamily: vFontFamily,
fontSize: styleBuilder.getStyle().fontSize,
color: vColorSemaphoreText,
backgroundColor: vColorSemaphore,
textAlign: 'right',
paddingLeft: '4px'
};
if (vSpecialF.substring(vSpecialF.length - 1) === '%' && vNumMeasures > 1) {
cellElement = (
<td key={nMeasures22} className={'grid-cells-small' + sufixCells} style={cellStyle}>
{columnNumber}
</td>
);
} else {
cellElement = (
<td key={nMeasures22} className={'grid-cells' + sufixCells} style={cellStyle}>
{columnNumber}
</td>
);
}
} else {
const cellStyle = {
fontFamily: vFontFamily,
...styleBuilder.getStyle(),
textAlign: 'right',
paddingRight: '4px'
};
if (vSpecialF.substring(vSpecialF.length - 1) === '%' && vNumMeasures > 1) {
cellElement = (
<td key={nMeasures22} className={'grid-cells-small' + sufixCells} style={cellStyle}>
{columnNumber}
</td>
);
} else {
cellElement = (
<td key={nMeasures22} className={'grid-cells' + sufixCells} style={cellStyle}>
{columnNumber}
</td>
);
}
}
measurementCells.push(cellElement);
}
return (
<React.Fragment>
{measurementCells}
</React.Fragment>
);
}
}
ElseDimensionMeasures.propTypes = {
vFontFamily: PropTypes.any,
vSeparatorCols: PropTypes.any,
measure_count: PropTypes.any,
sufixCells: PropTypes.any,
vSymbolForNulls: PropTypes.any,
vLetterSize: PropTypes.any,
vColorMetric1: PropTypes.any,
vColorMetric1Text: PropTypes.any,
vColorMetric2: PropTypes.any,
vColorMetric2Text: PropTypes.any,
vColorMetric3: PropTypes.any,
vColorMetric3Text: PropTypes.any,
vAllSemaphores: PropTypes.any,
ConceptMatrixPivot: PropTypes.any,
ConceptsAffectedMatrix: PropTypes.any,
vAllMetrics: PropTypes.any,
MetricsAffectedMatrix: PropTypes.any,
vCritic: PropTypes.any,
vMMedium: PropTypes.any,
vNumMeasures: PropTypes.any,
vNumMeasures2: PropTypes.any,
MeasuresFormat: PropTypes.any,
rowNumber: PropTypes.any,
columnText: PropTypes.any,
styleBuilder: PropTypes.any
};
export default ElseDimensionMeasures;

73
src/excel-export.js Normal file
View File

@@ -0,0 +1,73 @@
import $ from 'jquery';
const isIE = /* @cc_on!@*/false || Boolean(document.documentMode);
const isChrome = Boolean(window.chrome) && Boolean(window.chrome.webstore);
const isSafari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0;
const isFirefox = typeof InstallTrigger !== 'undefined';
export function enableExcelExport (layout, f) {
let myTitle = '';
let mySubTitle = '';
let myFootNote = '';
if (layout.title.length > 0) {
myTitle += '<p style="font-size:15pt"><b>';
myTitle += layout.title;
myTitle += '</b></p>';
}
if (layout.subtitle.length > 0) {
mySubTitle += '<p style="font-size:11pt">';
mySubTitle += layout.subtitle;
mySubTitle += '</p>';
}
if (layout.footnote.length > 0) {
myFootNote += '<p style="font-size:11pt"><i>Note:</i>';
myFootNote += layout.footnote;
myFootNote += '</p>';
}
$('.icon-xls').on('click', () => {
$('.header-wrapper th').children('.tooltip')
.remove(); // remove some popup effects when exporting
$('.header-wrapper th').children('.icon-xls')
.remove(); // remove the xls icon when exporting
if (isChrome || isSafari) {
const $clonedDiv = $('.data-table').clone(true); // .kpi-table a secas exporta la 1ªcol
let vEncodeHead = '<html><head><meta charset="UTF-8"></head>';
vEncodeHead += myTitle + mySubTitle + myFootNote;
const vEncode = encodeURIComponent($clonedDiv.html());
let vDecode = `${vEncodeHead + vEncode}</html>`;
$clonedDiv.find('tr.header');
vDecode = vDecode.split('%3E.%3C').join('%3E%3C');
window.open(`data:application/vnd.ms-excel,${vDecode}`);
$.preventDefault();
}
if (isIE) {
let a = '<html><head><meta charset="UTF-8"></head>';
a += myTitle + mySubTitle + myFootNote;
a += f;
a = a.split('>.<').join('><');
a += '</html>';
const w = window.open();
w.document.open();
w.document.write(a);
w.document.close();
w.document.execCommand('SaveAs', true, 'Analysis.xls' || 'c:\TMP');
w.close();
}
if (isFirefox) {
const $clonedDiv = $('.data-table').clone(true);// .kpi-table a secas exporta la 1ªcol
let vEncodeHead = '<html><head><meta charset="UTF-8"></head>';
vEncodeHead += myTitle + mySubTitle + myFootNote;
const vEncode = encodeURIComponent($clonedDiv.html());
let vDecode = `${vEncodeHead + vEncode}</html>`;
$clonedDiv.find('tr.header');
vDecode = vDecode.split('>.<').join('><');
window.open(`data:application/vnd.ms-excel,${vDecode}`);
$.preventDefault();
}
});
}

26
src/export-button.jsx Normal file
View File

@@ -0,0 +1,26 @@
import React from 'react';
import PropTypes from 'prop-types';
// TODO: move interaction logic in here from excel-export.js
class ExportButton extends React.PureComponent {
render () {
const { excelExport } = this.props;
return excelExport === true && (
<input
className="icon-xls"
src="/Extensions/qlik-smart-pivot/Excel.png"
type="image"
/>
);
}
}
ExportButton.defaultProps = {
excelExport: false
};
ExportButton.propTypes = {
excelExport: PropTypes.bool
};
export default ExportButton;

360
src/header-wrapper.jsx Normal file
View File

@@ -0,0 +1,360 @@
import React, { PureComponent, Fragment } from 'react';
import PropTypes from 'prop-types';
import ExportButton from './export-button.jsx';
/* TODO: the different render methods are very similar, split it into a few components
and try to get rid of some duplication */
class HeaderWrapper extends PureComponent {
getBaseCSS () {
const {
vHeaderColorText,
vFontFamily,
vHeaderColorSchema,
vHeaderAlignText
} = this.props;
const baseCSS = {
backgroundColor: vHeaderColorSchema,
color: vHeaderColorText,
fontFamily: vFontFamily,
textAlign: vHeaderAlignText
};
return baseCSS;
}
renderSecondDimensionTitles () {
const {
vFontFamily,
vLetterSizeHeader,
vExportToExcel,
sufixCells,
vNumDims,
measure_count,
LabelsArray,
SecondHeader,
vSeparatorCols,
nSecond,
vLetterSize,
ExtraLabelsArray
} = this.props;
const baseCSS = this.getBaseCSS();
if (vNumDims === 2) {
if (measure_count > 1) {
const thStyle = {
...baseCSS,
cursor: 'default',
fontSize: `${16 + vLetterSizeHeader} px`,
height: '80px',
verticalAlign: 'middle',
width: '230px'
};
return (
<Fragment key="second-dimension-titles">
<th
className="fdim-cells"
padding-left="20px"
rowSpan="2"
style={thStyle}
>
<ExportButton excelExport={vExportToExcel} />
{LabelsArray[0]}
</th>
{SecondHeader.map((header, index) => {
const emptyStyle = {
color: 'white',
fontFamily: vFontFamily,
fontSize: `${13 + vLetterSizeHeader} px`
};
const style = {
...baseCSS,
fontSize: `${14 + vLetterSizeHeader} px`,
height: '45px',
verticalAlign: 'middle'
};
return (
<Fragment key={index}>
{vSeparatorCols && index > 0 && (
<th
className="empty"
style={emptyStyle}
>
*
</th>
)}
<th
className={`grid-cells2${sufixCells}`}
colSpan={measure_count}
style={style}
>
{header}
</th>
</Fragment>
);
})}
</Fragment>
);
}
const fDimCellsStyle = {
...baseCSS,
cursor: 'default',
fontSize: `${16 + vLetterSizeHeader} px`,
height: '70px',
verticalAlign: 'middle',
width: '230px'
};
return (
<Fragment>
<th
className="fdim-cells"
style={fDimCellsStyle}
>
<ExportButton excelExport={vExportToExcel} />
{LabelsArray[0] + ExtraLabelsArray[0]}
</th>
{SecondHeader.map((entry, entryIndex) => {
// TODO: seperator element is reused a bunch, only difference being font-size
const hasSeperator = vSeparatorCols && nSecond > 0;
const seperatorStyle = {
color: 'white',
fontFamily: vFontFamily,
fontSize: `${12 + vLetterSize} px`
};
const seperatorElement = (
<th
className="empty"
style={seperatorStyle}
>
*
</th>
);
let sufixWrap = '';
if ((entry.length > 11 && vLetterSizeHeader === 0) || (entry.length > 12 && vLetterSizeHeader === -2)) {
sufixWrap = '70';
} else {
sufixWrap = 'Empty';
}
const gridCells2Style = {
...baseCSS,
fontSize: `${14 + vLetterSizeHeader} px`,
height: '70px',
verticalAlign: 'middle'
};
const wrapStyle = {
fontFamily: vFontFamily
};
return (
<Fragment key={entryIndex}>
{hasSeperator && seperatorElement}
<th
className={`grid-cells2${sufixCells}`}
style={gridCells2Style}
>
<span
className={`wrapclass${sufixWrap}`}
style={wrapStyle}
>
{entry}
</span>
</th>
</Fragment>
);
})}
</Fragment>
);
}
}
renderSecondDimensionSubTitles () {
const {
vFontFamily,
vLetterSizeHeader,
sufixCells,
LabelsArray,
SecondHeader,
vSeparatorCols,
vLetterSize,
MeasuresFormat,
ExtraLabelsArray
} = this.props;
const baseCSS = this.getBaseCSS();
return SecondHeader.map((header, index) => {
const emptyStyle = {
color: 'white',
fontFamily: vFontFamily,
fontSize: `${12 + vLetterSizeHeader} px`
};
return (
<Fragment key={index}>
{vSeparatorCols && index > 0 && (
<th
className="empty"
style={emptyStyle}
>
*
</th>
)}
{MeasuresFormat.map((measureFormat, measureFormatIndex) => {
if (measureFormat.substring(measureFormat.length - 1) === '%') {
const cells2SmallStyle = {
...baseCSS,
cursor: 'default',
fontSize: `${13 + vLetterSizeHeader} px`,
height: '25px',
verticalAlign: 'middle'
};
return (
<th key={measureFormatIndex} className={'grid-cells2-small' + sufixCells} style={cells2SmallStyle}>
<span className="wrapclass25">
{LabelsArray[measureFormatIndex + 1]}
{ExtraLabelsArray[measureFormatIndex]}
</span>
</th>
);
}
const cells2Style = {
...baseCSS,
cursor: 'default',
fontSize: `${14 + vLetterSizeHeader} px`,
height: '25px',
verticalAlign: 'middle'
};
return (
<th key={measureFormatIndex} className={'grid-cells2' + sufixCells} style={cells2Style}>
<span className="wrapclass25">
{LabelsArray[measureFormatIndex + 1]}
{ExtraLabelsArray[measureFormatIndex]}
</span>
</th>
);
})}
</Fragment>
);
});
}
renderMeasureInfos () {
const {
vFontFamily,
vLetterSizeHeader,
dim_count,
vExtraLabel,
sufixCells,
measureInfos
} = this.props;
const baseCSS = this.getBaseCSS();
if (dim_count === 1) {
return measureInfos.map((measureInfo, measureInfoIndex) => {
let sufixWrap = '';
if (((measureInfo.qFallbackTitle + vExtraLabel).length > 11 && vLetterSizeHeader === 0)
|| ((measureInfo.qFallbackTitle + vExtraLabel).length > 12 && vLetterSizeHeader === -2)) {
sufixWrap = '70';
} else {
sufixWrap = 'Empty';
}
const thStyle = {
...baseCSS,
cursor: 'default',
fontSize: `${15 + vLetterSizeHeader} px`,
height: '70px',
verticalAlign: 'middle'
};
return (
<th key={measureInfoIndex} className={'grid-cells2' + sufixCells} style={thStyle}>
<span className={'wrapclass' + sufixWrap} style={{ fontFamily: vFontFamily }}>
{measureInfo.qFallbackTitle + vExtraLabel}
</span>
</th>
);
});
}
return null;
}
renderDimensionInfos () {
const {
dimensionInfos,
vLetterSizeHeader,
vExportToExcel
} = this.props;
const baseCSS = this.getBaseCSS();
return dimensionInfos.map((dimensionInfo, dimensionInfoIndex) => {
// TODO: move static properties to css file
const style = {
...baseCSS,
cursor: 'default',
fontSize: `${17 + vLetterSizeHeader} px`,
height: '70px',
verticalAlign: 'middle',
width: '230px'
};
return (
<th
className="fdim-cells"
key={dimensionInfoIndex}
style={style}
>
<ExportButton excelExport={vExportToExcel} />
{dimensionInfo.qFallbackTitle}
</th>
);
});
}
render () {
const { vNumDims, measure_count } = this.props;
return (
<div className="header-wrapper">
<table className="header">
<tbody>
<tr>
{this.renderDimensionInfos()}
{this.renderMeasureInfos()}
{this.renderSecondDimensionTitles()}
</tr>
{ vNumDims === 2 && measure_count > 1 && (
<tr>
{this.renderSecondDimensionSubTitles()}
</tr>
)}
</tbody>
</table>
</div>
);
}
}
// TODO: make any, object and array forbidden
HeaderWrapper.propTypes = {
vHeaderColorText: PropTypes.any,
vFontFamily: PropTypes.any,
vHeaderColorSchema: PropTypes.any,
vExportToExcel: PropTypes.any,
vNumDims: PropTypes.any,
dimensionInfos: PropTypes.any,
vLetterSizeHeader: PropTypes.any,
vHeaderAlignText: PropTypes.any,
MeasuresFormat: PropTypes.any,
measure_count: PropTypes.any,
sufixCells: PropTypes.any,
LabelsArray: PropTypes.any,
SecondHeader: PropTypes.any,
vSeparatorCols: PropTypes.any,
nSecond: PropTypes.any,
vLetterSize: PropTypes.any,
ExtraLabelsArray: PropTypes.any,
dim_count: PropTypes.any,
vExtraLabel: PropTypes.any,
measureInfos: PropTypes.any
};
export default HeaderWrapper;

View File

@@ -1,791 +1,37 @@
import $ from 'jquery';
import style from 'text-loader!./PLSmartPivot.css';
import '@babel/polyfill';
import paint from './paint';
$('<style>').html(style).appendTo('head');
import definition from './definition';
import './main.less';
export default {
initialProperties: {
version: 1.0,
qHyperCubeDef: {
qDimensions: [],
qMeasures: [],
qInitialDataFetch: [{
qWidth: 10,
qHeight: 1000
}]
},
},
definition: {
type: 'items',
component: 'accordion',
items: {
dimensions: {
uses: 'dimensions',
min: 1,
max: 2
},
measures: {
uses: 'measures',
min: 1,
max: 9
},
sorting: {
uses: 'sorting'
},
settings: {
uses: 'settings',
items: {
Pagination: {
type: 'items',
label: 'Pagination',
items: {
MaxPaginationLoops: {
ref: 'maxloops',
type: 'number',
component: 'dropdown',
label: 'Max Pagination Loops',
options:
[{
value: 1,
label: '10k cells'
}, {
value: 2,
label: '20k cells'
}, {
value: 3,
label: '30k cells'
}, {
value: 4,
label: '40k cells'
}, {
value: 5,
label: '50k cells'
}, {
value: 6,
label: '60k cells'
}, {
value: 7,
label: '70k cells'
}, {
value: 8,
label: '80k cells'
}, {
value: 9,
label: '90k cells'
}, {
value: 10,
label: '100k cells'
}
],
defaultValue: 2,
},
ErrorMessage: {
ref: 'errormessage',
label: 'Default error message',
type: 'string',
defaultValue: 'Ups! It seems you asked for too many data. Please filter more to see the whole picture.',
},
},
},
Header: {
type: 'items',
label: 'Header Format',
items: {
Align: {
ref: 'HeaderAlign',
translation: 'Header Alignment',
type: 'number',
component: 'buttongroup',
options: [{
value: 1,
label: 'Left'
}, {
value: 2,
label: 'Center'
}, {
value: 3,
label: 'Right'
}],
defaultValue: 2,
},
headercolors: {
ref: 'HeaderColorSchema',
type: 'string',
component: 'dropdown',
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',
},
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',
},
HeaderFontSize: {
ref: 'lettersizeheader',
translation: 'Font Size',
type: 'number',
component: 'buttongroup',
options: [{
value: 1,
label: 'Small'
}, {
value: 2,
label: 'Medium'
//}, {
// value: 3,
// label: "Large"
}],
defaultValue: 2
},
}
},
Formatted: {
type: 'items',
label: 'Table Format',
items: {
IndentBool: {
ref: 'indentbool',
type: 'boolean',
label: 'Indent',
defaultValue: true
},
SeparatorColumns: {
ref: 'separatorcols',
type: 'boolean',
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: function (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: function (data) {
return data.customfilebool == false;
}
},
BodyTextColor: {
ref: 'BodyTextColorSchema',
type: 'string',
component: 'dropdown',
label: 'Text Body 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: 'Black',
show: function (data) {
return data.customfilebool == false;
}
},
FontFamily: {
ref: 'FontFamily',
type: 'string',
component: 'dropdown',
label: 'FontFamily',
options:
[{
value: 'Arial',
label: 'Arial'
}, {
value: 'Calibri',
label: 'Calibri'
}, {
value: 'Comic Sans MS',
label: 'Comic Sans MS'
}, {
value: 'MS Sans Serif',
label: 'MS Sans Serif'
}, {
value: 'Tahoma',
label: 'Tahoma'
}, {
value: 'Verdana',
label: 'Verdana'
}
],
defaultValue: 'Calibri'
},
DataFontSize: {
ref: 'lettersize',
translation: 'Font Size',
type: 'number',
component: 'buttongroup',
options: [{
value: 1,
label: 'Small'
}, {
value: 2,
label: 'Medium'
//}, {
// value: 3,
// label: "Large"
}],
defaultValue: 2
},
ColumnWidthSlider: {
type: 'number',
component: 'slider',
label: 'Column Width',
ref: 'columnwidthslider',
min: 1,
max: 3,
step: 1,
defaultValue: 2
},
SymbolForNulls: {
ref: 'symbolfornulls',
label: 'Symbol for Nulls',
type: 'string',
defaultValue: ' '
},
AllowExportXLS: {
ref: 'allowexportxls',
type: 'boolean',
component: 'switch',
label: 'Allow export to Excel',
options: [{
value: true,
label: 'On'
}, {
value: false,
label: 'Off'
}],
defaultValue: true
},
FilterOnCellClick: {
ref: 'filteroncellclick',
type: 'boolean',
component: 'switch',
label: 'Filter data when cell clicked',
options: [{
value: true,
label: 'On'
}, {
value: false,
label: 'Off'
}],
defaultValue: true
}
}
},
ConceptSemaphores: {
type: 'items',
label: 'Concept Semaphores',
items: {
AllConcepts: {
ref: 'allsemaphores',
type: 'boolean',
component: 'switch',
label: 'All concepts affected',
options: [{
value: true,
label: 'On'
}, {
value: false,
label: 'Off'
}],
defaultValue: true
},
ConceptsAffected1: {
ref: 'conceptsemaphore1',
translation: 'Concept 1',
type: 'string',
defaultValue: '',
show: function (data) {
return data.allsemaphores == false;
}
},
ConceptsAffected2: {
ref: 'conceptsemaphore2',
translation: 'Concept 2',
type: 'string',
defaultValue: '',
show: function (data) {
return data.allsemaphores == false;
}
},
ConceptsAffected3: {
ref: 'conceptsemaphore3',
translation: 'Concept 3',
type: 'string',
defaultValue: '',
show: function (data) {
return data.allsemaphores == false;
}
},
ConceptsAffected4: {
ref: 'conceptsemaphore4',
translation: 'Concept 4',
type: 'string',
defaultValue: '',
show: function (data) {
return data.allsemaphores == false;
}
},
ConceptsAffected5: {
ref: 'conceptsemaphore5',
translation: 'Concept 5',
type: 'string',
defaultValue: '',
show: function (data) {
return data.allsemaphores == false;
}
},
ConceptsAffected6: {
ref: 'conceptsemaphore6',
translation: 'Concept 6',
type: 'string',
defaultValue: '',
show: function (data) {
return data.allsemaphores == false;
}
},
ConceptsAffected7: {
ref: 'conceptsemaphore7',
translation: 'Concept 7',
type: 'string',
defaultValue: '',
show: function (data) {
return data.allsemaphores == false;
}
},
ConceptsAffected8: {
ref: 'conceptsemaphore8',
translation: 'Concept 8',
type: 'string',
defaultValue: '',
show: function (data) {
return data.allsemaphores == false;
}
},
ConceptsAffected9: {
ref: 'conceptsemaphore9',
translation: 'Concept 9',
type: 'string',
defaultValue: '',
show: function (data) {
return data.allsemaphores == false;
}
},
ConceptsAffected10: {
ref: 'conceptsemaphore10',
translation: 'Concept 10',
type: 'string',
defaultValue: '',
show: function (data) {
return data.allsemaphores == false;
}
},
}
},
MetricSemaphores: {
type: 'items',
label: 'Metric Semaphores',
items: {
AllMetrics: {
ref: 'allmetrics',
type: 'boolean',
component: 'switch',
label: 'All metrics affected',
options: [{
value: true,
label: 'On'
}, {
value: false,
label: 'Off'
}],
defaultValue: false
},
MetricsAffected: {
ref: 'metricssemaphore',
translation: 'Metrics affected (1,2,4,...)',
type: 'string',
defaultValue: '0',
show: function (data) {
return data.allmetrics == false;
}
},
MetricStatus1: {
ref: 'metricsstatus1',
translation: 'Critic is less than',
type: 'number',
defaultValue: -0.1
},
ColorStatus1: {
ref: 'colorstatus1',
label: 'Critic Color Fill',
type: 'object',
component: 'color-picker',
defaultValue: {
index: 7,
color: '#f93f17'
}
},
ColorStatus1Text: {
ref: 'colorstatus1text',
label: 'Critic Color Text',
type: 'object',
component: 'color-picker',
defaultValue: {
index: 10,
color: '#ffffff'
}
},
MetricStatus2: {
ref: 'metricsstatus2',
translation: 'Medium is less than',
type: 'number',
defaultValue: 0
},
ColorStatus2: {
ref: 'colorstatus2',
label: 'Medium Color Fill',
type: 'object',
component: 'color-picker',
defaultValue: {
index: 8,
color: '#ffcf02'
}
},
ColorStatus2Text: {
ref: 'colorstatus2text',
label: 'Medium Color Text',
type: 'object',
component: 'color-picker',
defaultValue: {
index: 11,
color: '#000000'
}
},
ColorStatus3: {
ref: 'colorstatus3',
label: 'Success Color Fill',
type: 'object',
component: 'color-picker',
defaultValue: {
index: 9,
color: '#276e27'
}
},
ColorStatus3Text: {
ref: 'colorstatus3text',
label: 'Success Color Text',
type: 'object',
component: 'color-picker',
defaultValue: {
index: 10,
color: '#ffffff'
}
},
}
},
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',
},
}
},
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',
},
}
}
}
}
}
},
snapshot: {
canTakeSnapshot: true
},
controller: [
'$scope',
'$timeout',
function () { }
],
paint: function ($element) {
definition,
initialProperties: {
qHyperCubeDef: {
qDimensions: [],
qInitialDataFetch: [
{
qHeight: 1000,
qWidth: 10
}
],
qMeasures: []
}
},
paint ($element, layout) {
try {
paint($element, this);
paint($element, layout, this);
} catch (exception) {
console.error(exception); // eslint-disable-line no-console
throw exception;
}
catch (e) {
console.error(e); // eslint-disable-line no-console
throw e;
}
}
},
snapshot: {
canTakeSnapshot: true
},
version: 1.0
};

View File

@@ -1,17 +1,13 @@
@TableBorder: 1px solid #d3d3d3;
@KpiTableWidth: 230px;
.qv-object-qlik-smart-pivot {
@TableBorder: 1px solid #d3d3d3;
@KpiTableWidth: 230px;
._cell(@Width: 50px) {
min-width: @Width!important;
max-width: @Width!important;
cursor: pointer;
line-height: 1em!important;
}
.qv-object-PLSmartPivot {
* {
box-sizing: border-box;
}
._cell(@Width: 50px) {
min-width: @Width!important;
max-width: @Width!important;
cursor: pointer;
line-height: 1em!important;
}
div.qv-object-content-container {
overflow-x: scroll;
@@ -147,74 +143,73 @@
.grid-cells:before {
content: "\00a0";
}
}
.grid {
height: 50px;
width: 350px;
}
.grid {
height: 50px;
width: 350px;
}
.header-wrapper {
position: absolute;
top: 0;
z-index: 1;
}
/*popups for headers*/
.tooltip {
position: fixed !important;
color: RGB(70,70,70);
background-color: RGB(245,239,207);
text-align: center;
border: groove;
}
/*end popups*/
.row-wrapper {
position: absolute;
top: 97px;
height: 100% !Important;
overflow-x: hidden;
overflow-y: scroll;
padding: 0;
margin-top: 0;
}
.header-wrapper {
position: absolute;
top: 0;
z-index: 1;
}
/*estos dos hcen referencia a la primera columna*/
.kpi-table .fdim-cells {
line-height: 1em!important;
}
/*popups for headers*/
.tooltip {
position: fixed !important;
color: RGB(70,70,70);
background-color: RGB(245,239,207);
text-align: center;
border: groove;
}
.data-table .fdim-cells {
display: none;
}
/*end popups*/
.row-wrapper {
position: absolute;
top: 97px;
height: calc(~"100% - 97px");
overflow-x: hidden;
overflow-y: scroll;
padding: 0;
margin-top: 0;
}
.kpi-table {
width: @KpiTableWidth !important;
overflow: hidden !important;
display: table;
height: 100%;
z-index: 100;
left: 258px;
margin: 0;
padding: 0;
z-index: 999;
position: absolute;
top: 0;
left: 0;
border-right: 1px solid white;
box-shadow: 4px 2px 8px #e1e1e1;
}
.kpi-table .fdim-cells, .data-table td {
line-height: 1em!important;
}
.kpi-table .row-wrapper {
overflow: hidden;
}
.data-table .fdim-cells {
display: none;
}
.data-table {
width: 272px !important;
float: left;
display: table;
height: 100%;
z-index: 90;
position: absolute;
margin-left: @KpiTableWidth + 13px;
-ms-overflow-style: none;
.kpi-table {
width: @KpiTableWidth !important;
overflow: hidden !important;
display: table;
height: 100%;
margin: 0;
padding: 0;
z-index: 100;
position: absolute;
top: 0;
left: 0;
border-right: 1px solid white;
box-shadow: 4px 2px 8px #e1e1e1;
}
.kpi-table .row-wrapper {
overflow: hidden;
}
.data-table {
width: 272px !important;
float: left;
display: table;
height: 100%;
z-index: 90;
position: absolute;
margin-left: @KpiTableWidth + 13px;
-ms-overflow-style: none;
}
}

131
src/masking.js Normal file
View File

@@ -0,0 +1,131 @@
import { addSeparators } from './utilities';
export function ApplyPreMask (mask, value) { // aqui
if (mask.indexOf(';') >= 0) {
if (value >= 0) {
switch (mask.substring(0, mask.indexOf(';'))) {
case '#.##0':
return (addSeparators(value, '.', ',', 0));
case '#,##0':
return (addSeparators(value, ',', '.', 0));
case '+#.##0':
return (addSeparators(value, '.', ',', 0));
case '+#,##0':
return (addSeparators(value, ',', '.', 0));
default:
return (ApplyMask(mask.substring(0, mask.indexOf(';')), value));
}
} else {
const vMyValue = value * -1;
let vMyMask = mask.substring(mask.indexOf(';') + 1, mask.length);
vMyMask = vMyMask.replace('(', '');
vMyMask = vMyMask.replace(')', '');
switch (vMyMask) {
case '#.##0':
return (`(${addSeparators(vMyValue, '.', ',', 0)})`);
case '#,##0':
return (`(${addSeparators(vMyValue, ',', '.', 0)})`);
case '-#.##0':
return (`(${addSeparators(vMyValue, '.', ',', 0)})`);
case '-#,##0':
return (`(${addSeparators(vMyValue, ',', '.', 0)})`);
default:
return (`(${ApplyMask(vMyMask, vMyValue)})`);
}
}
} else {
return (ApplyMask(mask, value));
}
}
function ApplyMask (mask, value) {
if (!mask || isNaN(Number(value))) {
return value; // return as it is.
}
let isNegative, result, decimal, group, posLeadZero, posTrailZero, posSeparator,
part, szSep, integer,
// find prefix/suffix
len = mask.length,
start = mask.search(/[0-9\-\+#]/),
prefix = start > 0 ? mask.substring(0, start) : '',
// reverse string: not an ideal method if there are surrogate pairs
str = mask.split('').reverse()
.join(''),
end = str.search(/[0-9\-\+#]/),
offset = len - end,
substr = mask.substring(offset, offset + 1),
indx = offset + ((substr === '.' || (substr === ',')) ? 1 : 0),
suffix = end > 0 ? mask.substring(indx, len) : '';
// mask with prefix & suffix removed
mask = mask.substring(start, indx);
// convert any string to number according to formation sign.
value = mask.charAt(0) === '-' ? -value : Number(value);
isNegative = value < 0 ? value = -value : 0; // process only abs(), and turn on flag.
// search for separator for grp & decimal, anything not digit, not +/- sign, not #.
result = mask.match(/[^\d\-\+#]/g);
decimal = (result && result[result.length - 1]) || '.'; // treat the right most symbol as decimal
group = (result && result[1] && result[0]) || ','; // treat the left most symbol as group separator
// split the decimal for the format string if any.
mask = mask.split(decimal);
// Fix the decimal first, toFixed will auto fill trailing zero.
value = value.toFixed(mask[1] && mask[1].length);
value = String(Number(value)); // convert number to string to trim off *all* trailing decimal zero(es)
// fill back any trailing zero according to format
posTrailZero = mask[1] && mask[1].lastIndexOf('0'); // look for last zero in format
part = value.split('.');
// integer will get !part[1]
if (!part[1] || (part[1] && part[1].length <= posTrailZero)) {
value = (Number(value)).toFixed(posTrailZero + 1);
}
szSep = mask[0].split(group); // look for separator
mask[0] = szSep.join(''); // join back without separator for counting the pos of any leading 0.
posLeadZero = mask[0] && mask[0].indexOf('0');
if (posLeadZero > -1) {
while (part[0].length < (mask[0].length - posLeadZero)) {
part[0] = `0${part[0]}`;
}
} else if (Number(part[0]) === 0) {
part[0] = '';
}
value = value.split('.');
value[0] = part[0];
// process the first group separator from decimal (.) only, the rest ignore.
// get the length of the last slice of split result.
posSeparator = (szSep[1] && szSep[szSep.length - 1].length);
if (posSeparator) {
integer = value[0];
str = '';
offset = integer.length % posSeparator;
len = integer.length;
for (indx = 0; indx < len; indx++) {
str += integer.charAt(indx); // ie6 only support charAt for sz.
// -posSeparator so that won't trail separator on full length
// jshint -W018
if (!((indx - offset + 1) % posSeparator) && indx < len - posSeparator) {
str += group;
}
}
value[0] = str;
}
value[1] = (mask[1] && value[1]) ? decimal + value[1] : '';
// remove negative sign if result is zero
result = value.join('');
if (result === '0' || result === '') {
// remove negative sign if result is zero
isNegative = false;
}
// put back any negation, combine integer and fraction, and add back prefix & suffix
return prefix + ((isNegative ? '-' : '') + result) + suffix;
}

File diff suppressed because it is too large Load Diff

81
src/row-list.jsx Normal file
View File

@@ -0,0 +1,81 @@
import React from 'react';
import PropTypes from 'prop-types';
import StyleBuilder from './style-builder';
class RowList extends React.PureComponent {
generatePaddingTextElement (hasCustomFileStyle) {
const { vPadding, vFontFamily } = this.props;
if (vPadding && !hasCustomFileStyle) {
const paddingStyle = {
fontFamily: vFontFamily,
marginLeft: '15px'
};
return (
<span style={paddingStyle} />
);
}
return null;
}
render () {
const {
vLetterSize,
vCustomFileBool,
vFontFamily,
tableData,
MeasurementsComponent
} = this.props;
return (
<tbody>
{tableData.map((row, rowNumber) => {
const rowHeaderText = row[0] || '';
if (rowHeaderText === '-') {
return null;
}
const styleBuilder = new StyleBuilder(this.props);
if (vCustomFileBool) {
styleBuilder.parseCustomFileStyle(rowHeaderText);
} else {
styleBuilder.applyStandardAttributes(rowNumber);
styleBuilder.applyCustomStyle({ fontSize: (14 + vLetterSize) + 'px' });
}
const rowStyle = {
fontFamily: vFontFamily,
width: '230px',
...styleBuilder.getStyle()
};
const paddingTextElement = this.generatePaddingTextElement(styleBuilder.hasCustomFileStyle());
const measurementsProps = {
rowHeaderText,
rowNumber,
styleBuilder
};
return (
<tr key={rowNumber}>
<td
className="fdim-cells"
style={rowStyle}
>
{paddingTextElement}
{rowHeaderText}
</td>
<MeasurementsComponent
columnText={rowHeaderText}
{...this.props}
{...measurementsProps}
/>
</tr>
);
})}
</tbody>
);
}
}
RowList.propTypes = {
tableData: PropTypes.array.isRequired
};
export default RowList;

129
src/row-wrapper.jsx Normal file
View File

@@ -0,0 +1,129 @@
import $ from 'jquery';
import PropTypes from 'prop-types';
import React from 'react';
import ElseDimensionMeasures from './else-dimension-measures.jsx';
import RowList from './row-list.jsx';
import SingleDimensionMeasures from './single-dimension-measures.jsx';
const RowWrapper = props => {
const {
ConceptMatrix,
ConceptMatrixPivot,
vNumDims
} = props;
let MeasurementsComponent,
tableData;
if (vNumDims === 1) {
tableData = ConceptMatrix;
MeasurementsComponent = SingleDimensionMeasures;
} else {
tableData = ConceptMatrixPivot.filter(array => array.length);
MeasurementsComponent = ElseDimensionMeasures;
}
return (
<div className="row-wrapper">
<table>
<RowList
MeasurementsComponent={MeasurementsComponent}
tableData={tableData}
{...props}
/>
</table>
</div>
);
};
RowWrapper.propTypes = {
ConceptMatrix: PropTypes.array.isRequired,
ConceptMatrixPivot: PropTypes.array.isRequired
};
export default RowWrapper;
export async function prepareProps ({ state }) {
const { colors, layout, vAllSemaphores, vDynamicColorBody, vDynamicColorBodyP } = state;
const props = {
colors,
vCustomFileBool: layout.customfilebool,
vCustomFile: layout.customfile,
vPadding: layout.indentbool,
vPaddingText: '',
vGlobalComas: 0,
vGlobalComas2: 0,
vGlobalComment: 0,
vGlobalCommentColor: '',
vGlobalFontSize: 0,
vComas: 0,
vMedium: false,
vFontSize: '',
vColorText: layout.BodyTextColorSchema,
vDivide: 1,
vSymbolForNulls: layout.symbolfornulls,
vDynamicColorBody: 'vColLib' + layout.ColorSchema,
vDynamicColorBodyP: 'vColLib' + layout.ColorSchema + 'P',
vAllMetrics: layout.allmetrics,
MetricsAffectedMatrix: JSON.parse('[' + layout.metricssemaphore + ']'),
vColorMetric1: layout.colorstatus1.color,
vColorMetric2: layout.colorstatus2.color,
vColorMetric3: layout.colorstatus3.color,
vColorMetric1Text: layout.colorstatus1text.color,
vColorMetric2Text: layout.colorstatus2text.color,
vColorMetric3Text: layout.colorstatus3text.color,
vColorSemaphore: '',
vColorSemaphoreText: '',
vCritic: layout.metricsstatus1,
vMMedium: layout.metricsstatus2,
CustomArray: new Array(),
CustomArrayBasic: new Array(),
vNumCustomHeaders: 0,
vColumnText: '',
vColumnNum: '',
vMaskNum: 0,
StyleTags: '',
vColorSchema: colors[vDynamicColorBody],
vColorSchemaP: colors[vDynamicColorBodyP],
vAllSemaphores: layout.allsemaphores,
ConceptsAffectedMatrix: new Array(10)
};
if (vAllSemaphores == false) {
props.ConceptsAffectedMatrix[0] = layout.conceptsemaphore1;
props.ConceptsAffectedMatrix[1] = layout.conceptsemaphore2;
props.ConceptsAffectedMatrix[2] = layout.conceptsemaphore3;
props.ConceptsAffectedMatrix[3] = layout.conceptsemaphore4;
props.ConceptsAffectedMatrix[4] = layout.conceptsemaphore5;
props.ConceptsAffectedMatrix[5] = layout.conceptsemaphore6;
props.ConceptsAffectedMatrix[6] = layout.conceptsemaphore7;
props.ConceptsAffectedMatrix[7] = layout.conceptsemaphore8;
props.ConceptsAffectedMatrix[8] = layout.conceptsemaphore9;
props.ConceptsAffectedMatrix[9] = layout.conceptsemaphore10;
}
function ReadCustomSchema () {
var Url = '/Extensions/qlik-smart-pivot/' + props.vCustomFile;
return $.get(Url).then(function (response) {
var allTextLines = response.split(/\r\n|\n/);
var headers = allTextLines[0].split(';');
props.vNumCustomHeaders = headers.length;
for (var i = 0; i < allTextLines.length; i++) {
props.CustomArray[i] = new Array(headers.length);
var data = allTextLines[i].split(';');
if (data.length == headers.length) {
for (var j = 0; j < headers.length; j++) {
props.CustomArrayBasic[i] = data[0];
props.CustomArray[i][j] = data[j];
}
}
}
});
}
const hasCustomSchema = (props.vCustomFileBool && props.vCustomFile.length > 4);
const schemaPromise = hasCustomSchema ? ReadCustomSchema() : Promise.resolve();
await schemaPromise;
return props;
}

View File

@@ -0,0 +1,159 @@
import React from 'react';
import PropTypes from 'prop-types';
import { ApplyPreMask } from './masking';
import { addSeparators } from './utilities';
class SingleDimensionMeasures extends React.PureComponent {
render () {
const {
vFontFamily,
vSymbolForNulls,
vColorMetric1,
vColorMetric1Text,
vColorMetric2,
vColorMetric2Text,
vColorMetric3,
vColorMetric3Text,
ConceptMatrix,
vAllSemaphores,
ConceptsAffectedMatrix,
vAllMetrics,
MetricsAffectedMatrix,
vCritic,
vMMedium,
vNumMeasures,
MeasuresFormat,
rowNumber,
columnText,
styleBuilder
} = this.props;
// modified in here
let vColumnNum,
vMaskNum,
vColorSemaphore,
vColorSemaphoreText,
vDivide;
const measurementCells = [];
// TODO: map ConceptMatrix[rowNumber] into cells
for (var nMeasures2 = 1; nMeasures2 <= vNumMeasures; nMeasures2++) {
var vSpecialF = MeasuresFormat[nMeasures2 - 1].replace(/k|K|m|M/gi, '');
if (columnText.substring(0, 1) == '%') {
vColumnNum = ApplyPreMask('0,00%', ConceptMatrix[rowNumber][nMeasures2]);
vSpecialF = '0,00%';
} else {
const magnitude = MeasuresFormat[nMeasures2 - 1].substr(MeasuresFormat[nMeasures2 - 1].length - 1);
switch (magnitude.toLowerCase()) {
case 'k':
vDivide = 1000;
break;
case 'm':
vDivide = 1000000;
break;
default:
vDivide = 1;
break;
}
if (!isNaN(ConceptMatrix[rowNumber][nMeasures2])) {
vMaskNum = ConceptMatrix[rowNumber][nMeasures2];
if (vSpecialF.substring(vSpecialF.length - 1) == '%') {
vMaskNum = vMaskNum * 100;
}
switch (vSpecialF) {
case '#.##0':
vColumnNum = addSeparators((vMaskNum / vDivide), '.', ',', 0);
break;
case '#,##0':
vColumnNum = addSeparators((vMaskNum / vDivide), ',', '.', 0);
break;
default:
vColumnNum = ApplyPreMask(vSpecialF, (vMaskNum / vDivide));
break;
}
} else {
vColumnNum = vSymbolForNulls;
}
}
if (styleBuilder.hasComments()) {
vColumnNum = '.';
}
// apply the semaphore styles where needed
let cellStyle;
if ((vAllSemaphores || ConceptsAffectedMatrix.indexOf(columnText) >= 0) && (vAllMetrics || MetricsAffectedMatrix.indexOf(nMeasures2) >= 0) && !isNaN(ConceptMatrix[rowNumber][nMeasures2]) && !styleBuilder.hasComments()) {
if (ConceptMatrix[rowNumber][nMeasures2] < vCritic) {
vColorSemaphore = vColorMetric1;
vColorSemaphoreText = vColorMetric1Text;
} else {
if (ConceptMatrix[rowNumber][nMeasures2] < vMMedium) {
vColorSemaphore = vColorMetric2;
vColorSemaphoreText = vColorMetric2Text;
} else {
vColorSemaphore = vColorMetric3;
vColorSemaphoreText = vColorMetric3Text;
}
}
cellStyle = {
fontFamily: vFontFamily,
fontSize: styleBuilder.getStyle().fontSize,
color: vColorSemaphoreText,
backgroundColor: vColorSemaphore,
textAlign: 'right',
paddingLeft: '4px'
};
} else {
cellStyle = {
fontFamily: vFontFamily,
textAlign: 'right',
paddingLeft: '4px',
...styleBuilder.getStyle()
};
}
const measurementCell = (
<td key={nMeasures2} className="grid-cells' + sufixCells + '" style={cellStyle}>
{vColumnNum}
</td>
);
measurementCells.push(measurementCell);
}
return (
<React.Fragment>
{measurementCells}
</React.Fragment>
);
}
}
SingleDimensionMeasures.propTypes = {
vFontFamily: PropTypes.any,
vSymbolForNulls: PropTypes.any,
vColorMetric1: PropTypes.any,
vColorMetric1Text: PropTypes.any,
vColorMetric2: PropTypes.any,
vColorMetric2Text: PropTypes.any,
vColorMetric3: PropTypes.any,
vColorMetric3Text: PropTypes.any,
ConceptMatrix: PropTypes.any,
vAllSemaphores: PropTypes.any,
ConceptsAffectedMatrix: PropTypes.any,
vAllMetrics: PropTypes.any,
MetricsAffectedMatrix: PropTypes.any,
vCritic: PropTypes.any,
vMMedium: PropTypes.any,
vNumMeasures: PropTypes.any,
MeasuresFormat: PropTypes.any,
rowNumber: PropTypes.any,
columnText: PropTypes.any,
styleBuilder: PropTypes.any
};
export default SingleDimensionMeasures;

299
src/store.js Normal file
View File

@@ -0,0 +1,299 @@
import { onlyUnique } from './utilities';
function initialize ({ $element, layout, component }) {
const colors = {
vColLibClean: layout.collibclean,
vColLibSoft: layout.collibsoft,
vColLibDark: layout.collibdark,
vColLibNight: layout.collibnight,
vColLibRed: layout.collibred,
vColLibOrange: layout.colliborange,
vColLibBlue: layout.collibblue,
vColLibGreen: layout.collibgreen,
vColLibViolete: layout.collibviolete,
vColLibCustom: layout.collibcustom,
vColLibCleanP: layout.collibcleanp,
vColLibSoftP: layout.collibsoftp,
vColLibDarkP: layout.collibdarkp,
vColLibNightP: layout.collibnightp,
vColLibRedP: layout.collibredp,
vColLibOrangeP: layout.colliborangep,
vColLibBlueP: layout.collibbluep,
vColLibGreenP: layout.collibgreenp,
vColLibVioleteP: layout.collibvioletep,
vColLibCustomP: layout.collibcustomp
};
const nMeasAux = 0;
const vMaxLoops = layout.maxloops;
const vErrorMessage = layout.errormessage;
const vDynamicColorHeader = `vColLib${layout.HeaderColorSchema}`;
const vHeaderColorSchema = colors[vDynamicColorHeader];
const vExportToExcel = layout.allowexportxls;
const vHeaderColorText = layout.HeaderTextColorSchema;
const vHeaderAlign = layout.HeaderAlign;
let vHeaderAlignText = '';
switch (vHeaderAlign) {
case 1:
vHeaderAlignText = 'left';
break;
case 2:
vHeaderAlignText = 'center';
break;
case 3:
vHeaderAlignText = 'right';
break;
}
let vLetterSizeHeader = 0;
switch (layout.lettersizeheader) {
case 1:
vLetterSizeHeader = -2;
break;
case 2:
vLetterSizeHeader = 0;
break;
case 3:
vLetterSizeHeader = 2;
break;
}
let vDimName = '';
const ConceptMatrixFirst = new Array();
const ConceptMatrixSecond = new Array();
let SecondHeaderLength = 0;
const LabelsArray = new Array();
const ExtraLabelsArray = new Array();
let vExtraLabel = '';
const vExcelButtonCode = '';
const ArrayGetSelectedCount = new Array();
let vNumDims = 0;
let vNumMeasures = 0;
let vNumMeasures2 = 0;
const MeasuresFormat = new Array();
let sufixCells = '';
switch (layout.columnwidthslider) {
case 1:
sufixCells += '-s';
break;
case 2:
sufixCells = String(sufixCells);
break;
case 3:
sufixCells += '-l';
break;
default:
sufixCells = String(sufixCells);
break;
}
const dim_count = layout.qHyperCube.qDimensionInfo.length;
const measure_count = layout.qHyperCube.qMeasureInfo.length;
let vSeparatorCols = layout.separatorcols;
if (dim_count == 1) {
vSeparatorCols = false;
}
const vFontFamily = layout.FontFamily;
let lastrow = 0;
const ConceptMatrix = new Array();
let ConceptMatrixRowElem = new Array();
let ConceptMatrixColElem = new Array();
const ConceptMatrixColElemTable = new Array();
const ConceptMatrixPivot = new Array();
let ConceptMatrixFirstClean = new Array();
let vLetterSize = 0;
switch (layout.lettersize) {
case 1:
vLetterSize = -2;
break;
case 2:
vLetterSize = -1;
break;
case 3:
vLetterSize = 2;
break;
}
const nRows = component.backendApi.getRowCount();
const dimensionInfos = component.backendApi.getDimensionInfos();
LabelsArray.push(dimensionInfos[0].qFallbackTitle);
ArrayGetSelectedCount.concat(dimensionInfos.map(dimensionInfo => dimensionInfo.qStateCounts.qSelected));
vNumDims += dimensionInfos.length;
const measureInfos = component.backendApi.getMeasureInfos();
measureInfos.forEach(measureInfo => {
vDimName = measureInfo.qFallbackTitle;
LabelsArray.push(vDimName);
let mfor = '';
if (measureInfo.qNumFormat.qType == 'U' || measureInfo.qNumFormat.qFmt == '##############') {
mfor = '#.##0'; // in case of undefined
} else if (measureInfo.qNumFormat.qType == 'R') {
mfor = measureInfo.qNumFormat.qFmt;
mfor = mfor.replace(/(|)/gi, '');
} else {
mfor = measureInfo.qNumFormat.qFmt;
}
MeasuresFormat.push(mfor);
switch (mfor.substr(mfor.length - 1).toLowerCase()) {
case 'm':
vExtraLabel = ' (M)';
ExtraLabelsArray.push(' (M)');
break;
case 'k':
vExtraLabel = ' (k)';
ExtraLabelsArray.push(' (k)');
break;
default:
vExtraLabel = '';
ExtraLabelsArray.push('');
break;
}
vNumMeasures++;
});
component.backendApi.eachDataRow((t, a) => {
lastrow = t;
const vNumMeasuresPlus = vNumMeasures + 1;
ConceptMatrix[t] = new Array();
ConceptMatrix[t][0] = a[0].qText;
ConceptMatrixFirst[t] = a[0].qText;
ConceptMatrixRowElem[t] = a[0].qElemNumber;
let nMeasures = 0;
if (vNumDims == 1) {
for (nMeasures = 1; nMeasures <= vNumMeasures; nMeasures++) {
ConceptMatrix[t][nMeasures] = a[nMeasures].qNum;
}
} else {
ConceptMatrix[t][1] = a[1].qText;
ConceptMatrixColElem[t] = a[1].qElemNumber;
ConceptMatrixSecond[t] = a[1].qText;
// set the hipercube in a plain array without pivoting
for (nMeasures = 2; nMeasures <= vNumMeasuresPlus; nMeasures++) {
ConceptMatrix[t][nMeasures] = a[nMeasures].qNum;
}
}
});
ConceptMatrixFirstClean = ConceptMatrixFirst.filter(onlyUnique);
if (nRows >= (vMaxLoops * 1000)) {
alert(vErrorMessage);
}
if (vNumDims == 2) {
// new array with unique values for 2nd dim
var SecondHeader = ConceptMatrixSecond.filter(onlyUnique);// second dimension concepts
ConceptMatrixRowElem = ConceptMatrixRowElem.filter(onlyUnique);// first dimension concepts
ConceptMatrixColElem = ConceptMatrixColElem.filter(onlyUnique);// dimension code for further selections
const eo = ConceptMatrixColElem.length;
let vLoopColsMeasures = 1;
ConceptMatrixColElemTable[0] = ConceptMatrixColElem[0];
for (let xx = 0; xx < eo; xx++) {
if (vSeparatorCols && xx > 0) {
ConceptMatrixColElemTable[vLoopColsMeasures] = ConceptMatrixColElem[xx];
vLoopColsMeasures++;
}
for (let xxx = 0; xxx < vNumMeasures; xxx++) {
ConceptMatrixColElemTable[vLoopColsMeasures] = ConceptMatrixColElem[xx];
vLoopColsMeasures++;
}
}
SecondHeaderLength = SecondHeader.length;
vNumMeasures2 = vNumMeasures * SecondHeaderLength;
let ConceptPos = 0;
let nMeas3 = 0;
let vHeaderIndex = 0;
let MeasurePos = 0;
for (let nPivotElems = 0; nPivotElems <= lastrow; nPivotElems++) {
ConceptMatrixPivot[nPivotElems] = new Array();
ConceptPos = ConceptMatrixFirstClean.indexOf(ConceptMatrix[nPivotElems][0]);
ConceptMatrixPivot[ConceptPos][0] = ConceptMatrix[nPivotElems][0];
for (let nMeas2 = 1; nMeas2 <= measure_count; nMeas2++) {
nMeas3 = nMeas2 + 1;
vHeaderIndex = (SecondHeader.indexOf(ConceptMatrix[nPivotElems][1]) + 1);
MeasurePos = (vHeaderIndex * measure_count) + (nMeas2 - measure_count);
ConceptMatrixPivot[ConceptPos][MeasurePos] = ConceptMatrix[nPivotElems][nMeas3];
}
}
}
if (nRows > (lastrow + 1) && nRows <= (vMaxLoops * 1000)) {
const requestPage = [
{
qTop: lastrow + 1,
qLeft: 0,
qWidth: 10, // should be # of columns
qHeight: Math.min(1000, nRows - lastrow)
}
];
component.backendApi.getData(requestPage).then(() => {
component.paint($element);
});
}
const properties = {
ArrayGetSelectedCount,
ConceptMatrix,
ConceptMatrixColElem,
ConceptMatrixColElemTable,
ConceptMatrixRowElem,
ConceptMatrixFirstClean,
ConceptMatrixPivot,
vHeaderColorText,
vFontFamily,
vHeaderColorSchema,
vExportToExcel,
vNumDims,
nMeasAux,
dimensionInfos,
vLetterSizeHeader,
vHeaderAlignText,
MeasuresFormat,
measure_count,
vExcelButtonCode,
sufixCells,
LabelsArray,
SecondHeader,
vSeparatorCols,
nSecond: SecondHeaderLength - 1,
nSecond2: SecondHeaderLength - 1,
vLetterSize,
ExtraLabelsArray,
dim_count,
vExtraLabel,
vNumMeasures,
vNumMeasures2,
lastrow,
measureInfos
};
// TODO: figure out a reasonable datastructure and use these for component
const transformedProperties = {
dimensions: [],
headers: LabelsArray,
headerOptions: {
colorSchema: vHeaderColorSchema,
textColor: vHeaderColorText
},
options: {
fontFamily: vFontFamily
}
};
return {
colors,
dimensionInfos,
measureInfos,
properties,
transformedProperties
};
}
export default initialize;

112
src/style-builder.js Normal file
View File

@@ -0,0 +1,112 @@
function StyleBuilder (state) {
const {
CustomArray,
CustomArrayBasic,
vNumCustomHeaders,
vColorSchema,
vColorText,
vColorSchemaP,
vLetterSize,
colors
} = state;
let style = {
fontSize: `${14 + vLetterSize}px`
};
let hasComments = false;
let commentColor;
let hasCustomFileStyle = false;
function applyStandardAttributes (rowNumber) {
const isEven = rowNumber % 2 === 0;
style.backgroundColor = isEven ? vColorSchema : vColorSchemaP;
style.color = vColorText;
style.fontSize = `${14 + vLetterSize}px`;
}
function applyColor (color) {
style.backgroundColor = color;
commentColor = color;
}
const properties = {
'<comment>': () => { hasComments = true; },
// text
'<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?
'<white>': () => { style.color = 'white'; },
// font size
'<large>': () => { style.fontSize = `${15 + vLetterSize}px`; },
'<medium>': () => { style.fontSize = `${14 + vLetterSize}px`; },
'<small>': () => { style.fontSize = `${13 + vLetterSize}px`; },
// text alignment
'<center>': () => { style.textAlign = 'center'; }
};
// TODO: need to improve this, it has way too many false positives
function isCSSColor (property) {
const isHexColor = property.substring(0, 1) == '#';
const isRGBColor = property.substring(0, 3).toUpperCase() == 'RGB';
return isHexColor || isRGBColor;
}
function applyProperty (property) {
if (!property || property === 'none') {
return;
}
if (isCSSColor(property)) {
applyColor(property);
return;
}
if (properties[property]) {
properties[property]();
} else {
console.error(`Custom property ${property} does not exist`); // eslint-disable-line no-console
}
}
function applyCustomStyle (customStyle) {
style = {
...style,
...customStyle
};
}
function parseCustomFileStyle (columnText) {
hasCustomFileStyle = true;
for (let csvAttribute = 1; csvAttribute < vNumCustomHeaders; csvAttribute += 1) {
let customAttribute = '';
if (CustomArrayBasic.indexOf(columnText) < 0) {
customAttribute = 'none';
} else {
customAttribute = CustomArray[CustomArrayBasic.indexOf(columnText)][csvAttribute];
}
applyProperty(customAttribute);
}
}
return {
getCommentColor: () => commentColor,
getStyle: () => style,
hasCustomFileStyle: () => hasCustomFileStyle,
hasFontSize: () => Boolean(style.fontSize),
hasComments: () => hasComments,
applyStandardAttributes,
applyProperty,
applyCustomStyle,
parseCustomFileStyle
};
}
export default StyleBuilder;

23
src/utilities.js Normal file
View File

@@ -0,0 +1,23 @@
export function onlyUnique (value, index, self) {
return self.indexOf(value) === index;
}
export function addSeparators (nStr, thousandsSep, decimalSep, numDecimals) {
let x1;
nStr = nStr.toFixed(numDecimals);
const x = nStr.split('.');
x1 = x[0];
const x2 = x.length > 1 ? decimalSep + x[1] : '';
const rgx = /(\d+)(\d{3})/;
while (rgx.test(x1)) {
x1 = x1.replace(rgx, `$1${thousandsSep}$2`);
}
return x1 + x2;
}
export function Deferred () {
this.promise = new Promise((resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
});
}

View File

@@ -23,11 +23,15 @@ const config = {
root: '_'
},
},
// TODO: breaks core-js for some reason
// resolve: {
// extensions: ['js', 'jsx']
// },
module: {
rules: [
{
enforce: 'pre',
test: /\.js$/,
test: /\.(js|jsx)$/,
exclude: /(node_modules|Library)/,
loader: 'eslint-loader',
options: {
@@ -35,12 +39,16 @@ const config = {
}
},
{
test: /.js$/,
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
plugins: ['@babel/plugin-transform-async-to-generator'],
presets: [
'@babel/preset-env',
'@babel/preset-react'
]
}
}
},