Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
61b339b146 | ||
|
|
fc363d7739 | ||
|
|
35d4dde118 | ||
|
|
e70e76a401 | ||
|
|
34477d7ef1 | ||
|
|
b65d1c51fc | ||
|
|
9111ec762b | ||
|
|
2bdd98aaca | ||
|
|
d723451656 | ||
|
|
f2f201c6e2 | ||
|
|
8e1394e898 | ||
|
|
c69cfec533 | ||
|
|
c4a717bd77 | ||
|
|
31e9be5220 | ||
|
|
b979a579f9 | ||
|
|
6233b9dbae | ||
|
|
9b682e62f8 | ||
|
|
462b4a13a2 | ||
|
|
2c6d978333 | ||
|
|
d669457ed9 | ||
|
|
8ef5ef6450 | ||
|
|
f6e629d9eb | ||
|
|
2322a5cdab | ||
|
|
8a86fe4a30 | ||
|
|
08cba41e18 | ||
|
|
9cfbb148fb | ||
|
|
4fd1cc1c3f | ||
|
|
2bf9259fdc | ||
|
|
f0121b3a75 | ||
|
|
5012db27a8 | ||
|
|
ec6713112a | ||
|
|
86f009fd3f | ||
|
|
228053483a | ||
|
|
76d835c15b | ||
|
|
22004e30c6 | ||
|
|
d5662e2746 |
@@ -18,6 +18,14 @@ jobs:
|
||||
- run:
|
||||
name: Install dependencies
|
||||
command: npm install
|
||||
- run:
|
||||
name: BlackDuck scan
|
||||
command: curl -s https://blackducksoftware.github.io/hub-detect/hub-detect.sh | bash -s -- \
|
||||
--blackduck.url="https://qliktech.blackducksoftware.com" \
|
||||
--blackduck.trust.cert=true \
|
||||
--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
|
||||
|
||||
77
.eslintrc.js
77
.eslintrc.js
@@ -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
1
.gitattributes
vendored
@@ -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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Smart pivot",
|
||||
"description": "Formatted table for P&L reports.",
|
||||
"name": "P&L pivot",
|
||||
"description": "Profit & Loss reporting with color and font customizations.",
|
||||
"type": "visualization",
|
||||
"version": "X.Y.Z",
|
||||
"icon": "table",
|
||||
|
||||
176
package-lock.json
generated
176
package-lock.json
generated
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
161
src/data-table/data-cell.jsx
Normal file
161
src/data-table/data-cell.jsx
Normal file
@@ -0,0 +1,161 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { ApplyPreMask } from '../masking';
|
||||
import { addSeparators } from '../utilities';
|
||||
|
||||
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) === '%';
|
||||
let formattedMeasurementValue = '';
|
||||
if (isColumnPercentageBased) {
|
||||
if (isNaN(measurement.value)) {
|
||||
formattedMeasurementValue = styling.symbolForNulls;
|
||||
} else {
|
||||
formattedMeasurementValue = ApplyPreMask('0,00%', measurement.value);
|
||||
}
|
||||
} else {
|
||||
let magnitudeDivider;
|
||||
switch (measurement.magnitude.toLowerCase()) {
|
||||
case 'k':
|
||||
magnitudeDivider = 1000;
|
||||
break;
|
||||
case 'm':
|
||||
magnitudeDivider = 1000000;
|
||||
break;
|
||||
default:
|
||||
magnitudeDivider = 1;
|
||||
}
|
||||
const formattingStringWithoutMagnitude = measurement.format.replace(/k|K|m|M/gi, '');
|
||||
if (isNaN(measurement.value)) {
|
||||
formattedMeasurementValue = styling.symbolForNulls;
|
||||
} else {
|
||||
let preFormatValue = measurement.value;
|
||||
if (isColumnPercentageBased) {
|
||||
preFormatValue *= 100;
|
||||
}
|
||||
switch (formattingStringWithoutMagnitude) {
|
||||
case '#.##0':
|
||||
formattedMeasurementValue = addSeparators((preFormatValue / magnitudeDivider), '.', ',', 0);
|
||||
break;
|
||||
case '#,##0':
|
||||
formattedMeasurementValue = addSeparators((preFormatValue / magnitudeDivider), ',', '.', 0);
|
||||
break;
|
||||
default:
|
||||
formattedMeasurementValue = ApplyPreMask(
|
||||
formattingStringWithoutMagnitude,
|
||||
(preFormatValue / magnitudeDivider)
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return formattedMeasurementValue;
|
||||
}
|
||||
|
||||
function getSemaphoreColors (measurement, semaphoreColors) {
|
||||
if (measurement < semaphoreColors.status.critical) {
|
||||
return semaphoreColors.statusColors.critical;
|
||||
}
|
||||
if (measurement < 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 cellStyle = {
|
||||
fontFamily: styling.options.fontFamily,
|
||||
...styleBuilder.getStyle(),
|
||||
paddingLeft: '4px',
|
||||
textAlign: 'right'
|
||||
|
||||
};
|
||||
const { semaphoreColors } = styling;
|
||||
const isValidSemaphoreValue = !styleBuilder.hasComments() && !isNaN(measurement.value);
|
||||
const shouldHaveSemaphoreColors = semaphoreColors.fieldsToApplyTo.applyToAll || semaphoreColors.fieldsToApplyTo.specificFields.indexOf(measurement.parents.dimension1.header) !== -1;
|
||||
if (isValidSemaphoreValue && shouldHaveSemaphoreColors) {
|
||||
const { backgroundColor, color } = getSemaphoreColors(measurement, semaphoreColors);
|
||||
cellStyle = {
|
||||
backgroundColor,
|
||||
color,
|
||||
fontFamily: styling.options.fontFamily,
|
||||
fontSize: styleBuilder.getStyle().fontSize,
|
||||
paddingLeft: '4px',
|
||||
textAlign: 'right'
|
||||
};
|
||||
}
|
||||
|
||||
let cellClass = 'grid-cells';
|
||||
const shouldUseSmallCells = isColumnPercentageBased && data.headers.measurements.length > 1;
|
||||
if (shouldUseSmallCells) {
|
||||
cellClass = 'grid-cells-small';
|
||||
}
|
||||
|
||||
return (
|
||||
<td
|
||||
className={`${cellClass}${general.cellSuffix}`}
|
||||
onClick={this.handleSelect}
|
||||
style={cellStyle}
|
||||
>
|
||||
{formattedMeasurementValue}
|
||||
</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;
|
||||
28
src/data-table/header-padding.jsx
Normal file
28
src/data-table/header-padding.jsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const HeaderPadding = ({ styleBuilder, styling }) => {
|
||||
if (styling.usePadding && !styleBuilder.hasCustomFileStyle()) {
|
||||
const paddingStyle = {
|
||||
fontFamily: styling.options.fontFamily,
|
||||
marginLeft: '15px'
|
||||
};
|
||||
return (
|
||||
<span style={paddingStyle} />
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
HeaderPadding.propTypes = {
|
||||
styleBuilder: PropTypes.shape({
|
||||
hasCustomFileStyle: PropTypes.func.isRequired
|
||||
}).isRequired,
|
||||
styling: PropTypes.shape({
|
||||
options: PropTypes.shape({
|
||||
fontFamily: PropTypes.string.isRequired
|
||||
}).isRequired
|
||||
}).isRequired
|
||||
};
|
||||
|
||||
export default HeaderPadding;
|
||||
115
src/data-table/index.jsx
Normal file
115
src/data-table/index.jsx
Normal file
@@ -0,0 +1,115 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import StyleBuilder from '../style-builder';
|
||||
import DataCell from './data-cell.jsx';
|
||||
import HeaderPadding from './header-padding.jsx';
|
||||
import RowHeader from './row-header.jsx';
|
||||
import { injectSeparators } from '../utilities';
|
||||
|
||||
const DataTable = ({ data, general, qlik, renderData, styling }) => {
|
||||
const {
|
||||
headers: {
|
||||
dimension1,
|
||||
measurements
|
||||
},
|
||||
matrix
|
||||
} = data;
|
||||
|
||||
return (
|
||||
<div className="row-wrapper">
|
||||
<table>
|
||||
<tbody>
|
||||
{dimension1.map((dimensionEntry, dimensionIndex) => {
|
||||
const rowHeaderText = dimensionEntry.displayValue || '';
|
||||
if (rowHeaderText === '-') {
|
||||
return null;
|
||||
}
|
||||
const styleBuilder = new StyleBuilder(styling);
|
||||
if (styling.hasCustomFileStyle) {
|
||||
styleBuilder.parseCustomFileStyle(rowHeaderText);
|
||||
} else {
|
||||
styleBuilder.applyStandardAttributes(dimensionIndex);
|
||||
styleBuilder.applyCustomStyle({
|
||||
fontSize: `${14 + styling.options.fontSizeAdjustment}px`
|
||||
});
|
||||
}
|
||||
const rowStyle = {
|
||||
fontFamily: styling.options.fontFamily,
|
||||
width: '230px',
|
||||
...styleBuilder.getStyle()
|
||||
};
|
||||
|
||||
return (
|
||||
<tr key={dimensionEntry.displayValue}>
|
||||
<RowHeader
|
||||
entry={dimensionEntry}
|
||||
qlik={qlik}
|
||||
rowStyle={rowStyle}
|
||||
styleBuilder={styleBuilder}
|
||||
styling={styling}
|
||||
/>
|
||||
{renderData && injectSeparators(
|
||||
matrix[dimensionIndex],
|
||||
styling.useSeparatorColumns,
|
||||
{ atEvery: measurements.length }
|
||||
).map((measurementData, index) => {
|
||||
if (measurementData.isSeparator) {
|
||||
const separatorStyle = {
|
||||
color: 'white',
|
||||
fontFamily: styling.options.fontFamily,
|
||||
fontSize: `${12 + styling.options.fontSizeAdjustment}px`
|
||||
};
|
||||
|
||||
return (
|
||||
<td
|
||||
className="empty"
|
||||
key={`${dimensionEntry.displayValue}-${index}-separator`}
|
||||
style={separatorStyle}
|
||||
>
|
||||
*
|
||||
</td>
|
||||
);
|
||||
}
|
||||
const { dimension1: dimension1Info, dimension2, measurement } = measurementData.parents;
|
||||
const id = `${dimension1Info.elementNumber}-${dimension2 && dimension2.elementNumber}-${measurement.header}`;
|
||||
return (
|
||||
<DataCell
|
||||
data={data}
|
||||
general={general}
|
||||
key={`${dimensionEntry.displayValue}-${id}`}
|
||||
measurement={measurementData}
|
||||
qlik={qlik}
|
||||
styleBuilder={styleBuilder}
|
||||
styling={styling}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
DataTable.defaultProps = {
|
||||
renderData: true
|
||||
};
|
||||
|
||||
DataTable.propTypes = {
|
||||
data: PropTypes.shape({
|
||||
headers: PropTypes.shape({
|
||||
dimension1: PropTypes.array.isRequired
|
||||
}).isRequired,
|
||||
matrix: PropTypes.arrayOf(PropTypes.array.isRequired).isRequired
|
||||
}).isRequired,
|
||||
general: PropTypes.shape({}).isRequired,
|
||||
qlik: PropTypes.shape({}).isRequired,
|
||||
renderData: PropTypes.bool,
|
||||
styling: PropTypes.shape({
|
||||
hasCustomFileStyle: PropTypes.bool.isRequired
|
||||
}).isRequired
|
||||
};
|
||||
|
||||
export default DataTable;
|
||||
49
src/data-table/row-header.jsx
Normal file
49
src/data-table/row-header.jsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import HeaderPadding from './header-padding.jsx';
|
||||
|
||||
class RowHeader extends React.PureComponent {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
this.handleSelect = this.handleSelect.bind(this);
|
||||
}
|
||||
|
||||
handleSelect () {
|
||||
const { entry, qlik } = this.props;
|
||||
qlik.backendApi.selectValues(0, [entry.elementNumber], true);
|
||||
}
|
||||
|
||||
render () {
|
||||
const { entry, rowStyle, styleBuilder, styling } = this.props;
|
||||
return (
|
||||
<td
|
||||
className="fdim-cells"
|
||||
onClick={this.handleSelect}
|
||||
style={rowStyle}
|
||||
>
|
||||
<HeaderPadding
|
||||
styleBuilder={styleBuilder}
|
||||
styling={styling}
|
||||
/>
|
||||
{entry.displayValue}
|
||||
</td>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
RowHeader.propTypes = {
|
||||
entry: PropTypes.shape({
|
||||
displayValue: PropTypes.string.isRequired
|
||||
}).isRequired,
|
||||
qlik: PropTypes.shape({
|
||||
backendApi: PropTypes.shape({
|
||||
selectValues: PropTypes.func.isRequired
|
||||
}).isRequired
|
||||
}).isRequired,
|
||||
rowStyle: PropTypes.shape({}).isRequired,
|
||||
styleBuilder: PropTypes.shape({}).isRequired,
|
||||
styling: PropTypes.shape({}).isRequired
|
||||
};
|
||||
|
||||
export default RowHeader;
|
||||
68
src/definition/color-library.js
Normal file
68
src/definition/color-library.js
Normal 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;
|
||||
96
src/definition/concept-semaphores.js
Normal file
96
src/definition/concept-semaphores.js
Normal 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;
|
||||
243
src/definition/formatted.js
Normal file
243
src/definition/formatted.js
Normal file
@@ -0,0 +1,243 @@
|
||||
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: 'QlikView Sans',
|
||||
label: 'QlikView Sans'
|
||||
},
|
||||
{
|
||||
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: 'QlikView Sans'
|
||||
},
|
||||
DataFontSize: {
|
||||
ref: 'lettersize',
|
||||
translation: 'Font Size',
|
||||
type: 'number',
|
||||
component: 'buttongroup',
|
||||
options: [
|
||||
{
|
||||
value: 1,
|
||||
label: 'Small'
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
label: 'Medium'
|
||||
}
|
||||
],
|
||||
defaultValue: 1
|
||||
},
|
||||
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
144
src/definition/header.js
Normal 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
41
src/definition/index.js
Normal 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;
|
||||
106
src/definition/metric-semaphores.js
Normal file
106
src/definition/metric-semaphores.js
Normal 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;
|
||||
63
src/definition/pagination.js
Normal file
63
src/definition/pagination.js
Normal 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;
|
||||
68
src/definition/pijama-color-library.js
Normal file
68
src/definition/pijama-color-library.js
Normal 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;
|
||||
73
src/excel-export.js
Normal file
73
src/excel-export.js
Normal 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
26
src/export-button.jsx
Normal 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;
|
||||
63
src/headers-table/column-header.jsx
Normal file
63
src/headers-table/column-header.jsx
Normal file
@@ -0,0 +1,63 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
class ColumnHeader extends React.PureComponent {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
this.handleSelect = this.handleSelect.bind(this);
|
||||
}
|
||||
|
||||
handleSelect () {
|
||||
const { entry, qlik } = this.props;
|
||||
qlik.backendApi.selectValues(1, [entry.elementNumber], true);
|
||||
}
|
||||
|
||||
render () {
|
||||
const { baseCSS, cellSuffix, colSpan, entry, styling } = this.props;
|
||||
const style = {
|
||||
...baseCSS,
|
||||
fontSize: `${14 + styling.headerOptions.fontSizeAdjustment} px`,
|
||||
height: '45px',
|
||||
verticalAlign: 'middle'
|
||||
};
|
||||
|
||||
return (
|
||||
<th
|
||||
className={`grid-cells2${cellSuffix}`}
|
||||
colSpan={colSpan}
|
||||
onClick={this.handleSelect}
|
||||
style={style}
|
||||
>
|
||||
{entry.displayValue}
|
||||
</th>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ColumnHeader.defaultProps = {
|
||||
cellSuffix: '',
|
||||
colSpan: 1
|
||||
};
|
||||
|
||||
ColumnHeader.propTypes = {
|
||||
baseCSS: PropTypes.shape({}).isRequired,
|
||||
cellSuffix: PropTypes.string,
|
||||
colSpan: PropTypes.number,
|
||||
entry: PropTypes.shape({
|
||||
elementNumber: PropTypes.number.isRequired,
|
||||
name: PropTypes.string.isRequired
|
||||
}).isRequired,
|
||||
qlik: PropTypes.shape({
|
||||
backendApi: PropTypes.shape({
|
||||
selectValues: PropTypes.func.isRequired
|
||||
}).isRequired
|
||||
}).isRequired,
|
||||
styling: PropTypes.shape({
|
||||
headerOptions: PropTypes.shape({
|
||||
fontSizeAdjustment: PropTypes.number.isRequired
|
||||
}).isRequired
|
||||
}).isRequired
|
||||
};
|
||||
|
||||
export default ColumnHeader;
|
||||
40
src/headers-table/export-column-header.jsx
Normal file
40
src/headers-table/export-column-header.jsx
Normal file
@@ -0,0 +1,40 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ExportButton from '../export-button.jsx';
|
||||
|
||||
const ExportColumnHeader = ({ baseCSS, title, allowExcelExport, hasSecondDimension, styling }) => {
|
||||
const rowSpan = hasSecondDimension ? 2 : 1;
|
||||
const style = {
|
||||
...baseCSS,
|
||||
cursor: 'default',
|
||||
fontSize: `${16 + styling.headerOptions.fontSizeAdjustment} px`,
|
||||
height: '80px',
|
||||
verticalAlign: 'middle',
|
||||
width: '230px'
|
||||
};
|
||||
|
||||
return (
|
||||
<th
|
||||
className="fdim-cells"
|
||||
rowSpan={rowSpan}
|
||||
style={style}
|
||||
>
|
||||
<ExportButton excelExport={allowExcelExport} />
|
||||
{title}
|
||||
</th>
|
||||
);
|
||||
};
|
||||
|
||||
ExportColumnHeader.propTypes = {
|
||||
allowExcelExport: PropTypes.bool.isRequired,
|
||||
baseCSS: PropTypes.shape({}).isRequired,
|
||||
hasSecondDimension: PropTypes.bool.isRequired,
|
||||
styling: PropTypes.shape({
|
||||
headerOptions: PropTypes.shape({
|
||||
fontSizeAdjustment: PropTypes.number.isRequired
|
||||
}).isRequired
|
||||
}).isRequired,
|
||||
title: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
export default ExportColumnHeader;
|
||||
137
src/headers-table/index.jsx
Normal file
137
src/headers-table/index.jsx
Normal file
@@ -0,0 +1,137 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ExportColumnHeader from './export-column-header.jsx';
|
||||
import ColumnHeader from './column-header.jsx';
|
||||
import MeasurementColumnHeader from './measurement-column-header.jsx';
|
||||
import { injectSeparators } from '../utilities';
|
||||
|
||||
const HeadersTable = ({ data, general, qlik, styling }) => {
|
||||
const baseCSS = {
|
||||
backgroundColor: styling.headerOptions.colorSchema,
|
||||
color: styling.headerOptions.textColor,
|
||||
fontFamily: styling.options.fontFamily,
|
||||
textAlign: styling.headerOptions.alignment
|
||||
};
|
||||
|
||||
const {
|
||||
dimension1,
|
||||
dimension2,
|
||||
measurements
|
||||
} = data.headers;
|
||||
|
||||
const hasSecondDimension = dimension2.length > 0;
|
||||
|
||||
return (
|
||||
<div className="header-wrapper">
|
||||
<table className="header">
|
||||
<tbody>
|
||||
<tr>
|
||||
<ExportColumnHeader
|
||||
allowExcelExport={general.allowExcelExport}
|
||||
baseCSS={baseCSS}
|
||||
hasSecondDimension={hasSecondDimension}
|
||||
styling={styling}
|
||||
title={dimension1[0].name}
|
||||
/>
|
||||
{!hasSecondDimension && measurements.map(measurementEntry => (
|
||||
<MeasurementColumnHeader
|
||||
baseCSS={baseCSS}
|
||||
general={general}
|
||||
hasSecondDimension={hasSecondDimension}
|
||||
key={`${measurementEntry.displayValue}-${measurementEntry.name}`}
|
||||
measurement={measurementEntry}
|
||||
styling={styling}
|
||||
/>
|
||||
))}
|
||||
{hasSecondDimension && injectSeparators(dimension2, styling.useSeparatorColumns).map((entry, index) => {
|
||||
if (entry.isSeparator) {
|
||||
const separatorStyle = {
|
||||
color: 'white',
|
||||
fontFamily: styling.options.fontFamily,
|
||||
fontSize: `${13 + styling.headerOptions.fontSizeAdjustment}px`
|
||||
};
|
||||
|
||||
return (
|
||||
<th
|
||||
className="empty"
|
||||
key={index}
|
||||
style={separatorStyle}
|
||||
>
|
||||
*
|
||||
</th>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<ColumnHeader
|
||||
baseCSS={baseCSS}
|
||||
cellSuffix={general.cellSuffix}
|
||||
colSpan={measurements.length}
|
||||
entry={entry}
|
||||
key={entry.displayValue}
|
||||
qlik={qlik}
|
||||
styling={styling}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</tr>
|
||||
{hasSecondDimension && (
|
||||
<tr>
|
||||
{injectSeparators(dimension2, styling.useSeparatorColumns).map((dimensionEntry, index) => {
|
||||
if (dimensionEntry.isSeparator) {
|
||||
const separatorStyle = {
|
||||
color: 'white',
|
||||
fontFamily: styling.options.fontFamily,
|
||||
fontSize: `${12 + styling.headerOptions.fontSizeAdjustment}px`
|
||||
};
|
||||
|
||||
return (
|
||||
<th
|
||||
className="empty"
|
||||
key={index}
|
||||
style={separatorStyle}
|
||||
>
|
||||
*
|
||||
</th>
|
||||
);
|
||||
}
|
||||
return measurements.map(measurementEntry => (
|
||||
<MeasurementColumnHeader
|
||||
baseCSS={baseCSS}
|
||||
dimensionEntry={dimensionEntry}
|
||||
general={general}
|
||||
hasSecondDimension={hasSecondDimension}
|
||||
key={`${measurementEntry.displayValue}-${measurementEntry.name}-${dimensionEntry.name}`}
|
||||
measurement={measurementEntry}
|
||||
styling={styling}
|
||||
/>
|
||||
));
|
||||
})}
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
HeadersTable.propTypes = {
|
||||
data: PropTypes.shape({
|
||||
headers: PropTypes.shape({
|
||||
dimension1: PropTypes.array,
|
||||
dimension2: PropTypes.array,
|
||||
measurements: PropTypes.array
|
||||
})
|
||||
}).isRequired,
|
||||
general: PropTypes.shape({}).isRequired,
|
||||
qlik: PropTypes.shape({
|
||||
backendApi: PropTypes.shape({
|
||||
selectValues: PropTypes.func.isRequired
|
||||
}).isRequired
|
||||
}).isRequired,
|
||||
styling: PropTypes.shape({
|
||||
headerOptions: PropTypes.shape({}),
|
||||
options: PropTypes.shape({})
|
||||
}).isRequired
|
||||
};
|
||||
|
||||
export default HeadersTable;
|
||||
77
src/headers-table/measurement-column-header.jsx
Normal file
77
src/headers-table/measurement-column-header.jsx
Normal file
@@ -0,0 +1,77 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const MeasurementColumnHeader = ({ baseCSS, general, hasSecondDimension, measurement, styling }) => {
|
||||
const title = `${measurement.name} ${measurement.magnitudeLabelSuffix}`;
|
||||
const { fontSizeAdjustment } = styling.headerOptions;
|
||||
if (hasSecondDimension) {
|
||||
const isPercentageFormat = measurement.format.substring(measurement.format.length - 1) === '%';
|
||||
let baseFontSize = 14;
|
||||
let cellClass = 'grid-cells2';
|
||||
if (isPercentageFormat) {
|
||||
baseFontSize = 13;
|
||||
cellClass = 'grid-cells2-small';
|
||||
}
|
||||
const cellStyle = {
|
||||
...baseCSS,
|
||||
cursor: 'default',
|
||||
fontSize: `${baseFontSize + fontSizeAdjustment} px`,
|
||||
height: '25px',
|
||||
verticalAlign: 'middle'
|
||||
};
|
||||
return (
|
||||
<th
|
||||
className={`${cellClass}${general.cellSuffix}`}
|
||||
style={cellStyle}
|
||||
>
|
||||
<span className="wrapclass25">
|
||||
{title}
|
||||
</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',
|
||||
verticalAlign: 'middle'
|
||||
};
|
||||
return (
|
||||
<th
|
||||
className={`grid-cells2 ${general.cellSuffix}`}
|
||||
style={style}
|
||||
>
|
||||
<span
|
||||
className={`wrapclass${suffixWrap}`}
|
||||
style={{ fontFamily: styling.headerOptions.fontFamily }}
|
||||
>
|
||||
{title}
|
||||
</span>
|
||||
</th>
|
||||
);
|
||||
};
|
||||
|
||||
MeasurementColumnHeader.defaultProps = {
|
||||
hasSecondDimension: false
|
||||
};
|
||||
|
||||
MeasurementColumnHeader.propTypes = {
|
||||
baseCSS: PropTypes.shape({}).isRequired,
|
||||
general: PropTypes.shape({
|
||||
cellSuffix: PropTypes.string.isRequired
|
||||
}).isRequired,
|
||||
hasSecondDimension: PropTypes.bool,
|
||||
measurement: PropTypes.shape({
|
||||
name: PropTypes.string.isRequired
|
||||
}).isRequired,
|
||||
styling: PropTypes.shape({
|
||||
headerOptions: PropTypes.shape({
|
||||
fontSizeAdjustment: PropTypes.number.isRequired
|
||||
}).isRequired
|
||||
}).isRequired
|
||||
};
|
||||
|
||||
export default MeasurementColumnHeader;
|
||||
814
src/index.js
814
src/index.js
@@ -1,791 +1,45 @@
|
||||
import paint from './paint.jsx';
|
||||
import definition from './definition';
|
||||
import './main.less';
|
||||
|
||||
import $ from 'jquery';
|
||||
import style from 'text-loader!./PLSmartPivot.css';
|
||||
import paint from './paint';
|
||||
|
||||
$('<style>').html(style).appendTo('head');
|
||||
if (!window._babelPolyfill) { // eslint-disable-line no-underscore-dangle
|
||||
require('@babel/polyfill'); // eslint-disable-line global-require
|
||||
}
|
||||
|
||||
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: []
|
||||
}
|
||||
},
|
||||
support: {
|
||||
export: true,
|
||||
exportData: true,
|
||||
snapshot: true
|
||||
},
|
||||
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
|
||||
};
|
||||
|
||||
342
src/initialize-transformed.js
Normal file
342
src/initialize-transformed.js
Normal file
@@ -0,0 +1,342 @@
|
||||
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
|
||||
};
|
||||
}
|
||||
|
||||
function getAlignment (option) {
|
||||
const alignmentOptions = {
|
||||
1: 'left',
|
||||
2: 'center',
|
||||
3: 'right'
|
||||
};
|
||||
|
||||
return alignmentOptions[option] || 'left';
|
||||
}
|
||||
|
||||
function getFontSizeAdjustment (option) {
|
||||
const fontSizeAdjustmentOptions = {
|
||||
1: -1,
|
||||
2: 1,
|
||||
3: 2
|
||||
};
|
||||
|
||||
return fontSizeAdjustmentOptions[option] || 0;
|
||||
}
|
||||
|
||||
function getCellSuffix (option) {
|
||||
const cellSuffixOptions = {
|
||||
1: '-s',
|
||||
3: '-l'
|
||||
};
|
||||
|
||||
return cellSuffixOptions[option] || '';
|
||||
}
|
||||
|
||||
function getMeasurementFormat (measurement) {
|
||||
if (measurement.qNumFormat.qType === 'U' || measurement.qNumFormat.qFmt === '##############') {
|
||||
return '#.##0';
|
||||
} else if (measurement.qNumFormat.qType === 'R') {
|
||||
return measurement.qNumFormat.qFmt.replace(/(|)/gi, '');
|
||||
}
|
||||
return measurement.qNumFormat.qFmt;
|
||||
}
|
||||
|
||||
function getMagnitudeLabelSuffix (magnitudeOption) {
|
||||
const magnitudeLabelSuffixOptions = {
|
||||
'k': ' (k)',
|
||||
'm': ' (m)'
|
||||
};
|
||||
|
||||
return magnitudeLabelSuffixOptions[magnitudeOption] || '';
|
||||
}
|
||||
|
||||
function generateMeasurements (information) {
|
||||
return information.map(measurement => {
|
||||
const format = getMeasurementFormat(measurement);
|
||||
const formatMagnitude = format.substr(format.length - 1).toLowerCase();
|
||||
const transformedMeasurement = {
|
||||
format,
|
||||
magnitudeLabelSuffix: getMagnitudeLabelSuffix(formatMagnitude),
|
||||
name: measurement.qFallbackTitle
|
||||
};
|
||||
|
||||
return transformedMeasurement;
|
||||
});
|
||||
}
|
||||
|
||||
function generateDimensionEntry (information, data) {
|
||||
return {
|
||||
displayValue: data.qText,
|
||||
elementNumber: data.qElemNumber,
|
||||
name: information.qFallbackTitle,
|
||||
value: data.qNum
|
||||
};
|
||||
}
|
||||
|
||||
function generateMatrixCell ({ cell, dimension1Information, dimension2Information, measurementInformation }) {
|
||||
const matrixCell = {
|
||||
displayValue: cell.qText,
|
||||
format: measurementInformation.format,
|
||||
magnitude: measurementInformation.magnitudeLabelSuffix.substring(
|
||||
measurementInformation.magnitudeLabelSuffix.length - 2,
|
||||
measurementInformation.magnitudeLabelSuffix.length - 1
|
||||
),
|
||||
magnitudeLabelSuffix: measurementInformation.magnitudeLabelSuffix,
|
||||
name: measurementInformation.name,
|
||||
parents: {
|
||||
dimension1: {
|
||||
elementNumber: dimension1Information.qElemNumber,
|
||||
header: dimension1Information.qText
|
||||
},
|
||||
measurement: {
|
||||
header: measurementInformation.name
|
||||
}
|
||||
},
|
||||
value: cell.qNum
|
||||
};
|
||||
|
||||
if (dimension2Information) {
|
||||
matrixCell.parents.dimension2 = {
|
||||
elementNumber: dimension2Information.qElemNumber
|
||||
};
|
||||
}
|
||||
|
||||
return matrixCell;
|
||||
}
|
||||
|
||||
let lastRow = 0;
|
||||
function generateDataSet (component, dimensionsInformation, measurementsInformation) {
|
||||
const dimension1 = [];
|
||||
const dimension2 = [];
|
||||
const measurements = generateMeasurements(measurementsInformation);
|
||||
let matrix = [];
|
||||
|
||||
let previousDim1Entry;
|
||||
const hasSecondDimension = dimensionsInformation.length > 1;
|
||||
component.backendApi.eachDataRow((rowIndex, row) => {
|
||||
lastRow += 1;
|
||||
const dimension1Entry = generateDimensionEntry(dimensionsInformation[0], row[0]);
|
||||
dimension1.push(dimension1Entry);
|
||||
let dimension2Entry;
|
||||
let firstDataCell = 1;
|
||||
if (hasSecondDimension) {
|
||||
dimension2Entry = generateDimensionEntry(dimensionsInformation[1], row[1]);
|
||||
dimension2.push(dimension2Entry);
|
||||
firstDataCell = 2;
|
||||
}
|
||||
const matrixRow = row
|
||||
.slice(firstDataCell, row.length)
|
||||
.map((cell, cellIndex) => {
|
||||
const measurementInformation = measurements[cellIndex];
|
||||
const dimension1Information = row[0]; // eslint-disable-line prefer-destructuring
|
||||
const dimension2Information = hasSecondDimension ? row[1] : null;
|
||||
const generatedCell = generateMatrixCell({
|
||||
cell,
|
||||
dimension1Information,
|
||||
dimension2Information,
|
||||
measurementInformation
|
||||
});
|
||||
|
||||
return generatedCell;
|
||||
});
|
||||
|
||||
if (hasSecondDimension) {
|
||||
const currentDim1Entry = row[0].qText;
|
||||
const isSameDimension1AsPrevious = currentDim1Entry === previousDim1Entry;
|
||||
if (isSameDimension1AsPrevious) {
|
||||
const updatedRow = matrix[matrix.length - 1].concat(matrixRow);
|
||||
|
||||
matrix = [
|
||||
...matrix.slice(0, matrix.length - 1),
|
||||
updatedRow
|
||||
];
|
||||
} else {
|
||||
matrix[matrix.length] = matrixRow;
|
||||
}
|
||||
previousDim1Entry = currentDim1Entry;
|
||||
} else {
|
||||
matrix[matrix.length] = matrixRow;
|
||||
}
|
||||
});
|
||||
|
||||
// filter header dimensions to only have distinct values
|
||||
|
||||
return {
|
||||
dimension1: distinctArray(dimension1),
|
||||
dimension2: distinctArray(dimension2),
|
||||
matrix,
|
||||
measurements
|
||||
};
|
||||
}
|
||||
|
||||
async function initializeTransformed ({ $element, layout, component }) {
|
||||
const colors = initializeColors({ layout });
|
||||
const dimensionsInformation = component.backendApi.getDimensionInfos();
|
||||
const measurementsInformation = component.backendApi.getMeasureInfos();
|
||||
const dimensionCount = layout.qHyperCube.qDimensionInfo.length;
|
||||
const rowCount = component.backendApi.getRowCount();
|
||||
const maxLoops = layout.maxloops;
|
||||
const {
|
||||
dimension1,
|
||||
dimension2,
|
||||
measurements,
|
||||
matrix
|
||||
} = generateDataSet(component, dimensionsInformation, measurementsInformation);
|
||||
|
||||
const customSchemaBasic = [];
|
||||
const customSchemaFull = [];
|
||||
let customHeadersCount = 0;
|
||||
|
||||
function readCustomSchema () {
|
||||
const url = `/Extensions/qlik-smart-pivot/${layout.customfile}`;
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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 = {
|
||||
data: {
|
||||
headers: {
|
||||
dimension1, // column headers
|
||||
dimension2, // parent row headers if exists
|
||||
measurements // row headers, looped for each dimension2 if exists
|
||||
},
|
||||
matrix, // 2d array of all rows/cells to render in body of datatable
|
||||
meta: {
|
||||
dimensionCount: dimensionsInformation.length
|
||||
}
|
||||
},
|
||||
general: {
|
||||
allowExcelExport: layout.allowexportxls,
|
||||
allowFilteringByClick: layout.filteroncellclick,
|
||||
cellSuffix: getCellSuffix(layout.columnwidthslider), // TOOD: move to matrix cells or is it headers.measurements?
|
||||
errorMessage: layout.errormessage,
|
||||
maxLoops
|
||||
},
|
||||
selection: {
|
||||
dimensionSelectionCounts: dimensionsInformation.map(dimensionInfo => dimensionInfo.qStateCounts.qSelected)
|
||||
},
|
||||
styling: {
|
||||
colors,
|
||||
customCSV: {
|
||||
basic: customSchemaBasic,
|
||||
count: customHeadersCount,
|
||||
full: customSchemaFull
|
||||
},
|
||||
hasCustomFileStyle: layout.customfilebool,
|
||||
headerOptions: {
|
||||
alignment: getAlignment(layout.HeaderAlign),
|
||||
colorSchema: colors[`vColLib${layout.HeaderColorSchema}`],
|
||||
fontSizeAdjustment: getFontSizeAdjustment(layout.lettersizeheader),
|
||||
textColor: layout.HeaderTextColorSchema
|
||||
},
|
||||
options: {
|
||||
backgroundColor: colors[`vColLib${layout.ColorSchema}`],
|
||||
backgroundColorOdd: colors[`vColLib${layout.ColorSchemaP}`],
|
||||
color: layout.BodyTextColorSchema,
|
||||
fontFamily: layout.FontFamily,
|
||||
fontSizeAdjustment: getFontSizeAdjustment(layout.lettersize)
|
||||
},
|
||||
semaphoreColors: {
|
||||
fieldsToApplyTo: {
|
||||
applyToAll: layout.allsemaphores,
|
||||
specificFields: [
|
||||
layout.conceptsemaphore1,
|
||||
layout.conceptsemaphore2,
|
||||
layout.conceptsemaphore3,
|
||||
layout.conceptsemaphore4,
|
||||
layout.conceptsemaphore5,
|
||||
layout.conceptsemaphore6,
|
||||
layout.conceptsemaphore7,
|
||||
layout.conceptsemaphore9,
|
||||
layout.conceptsemaphore10
|
||||
]
|
||||
},
|
||||
status: {
|
||||
critical: layout.metricstatus1,
|
||||
medium: layout.metricstatus2
|
||||
},
|
||||
statusColors: {
|
||||
critical: {
|
||||
backgroundColor: layout.colorstatus1.color,
|
||||
color: layout.colorstatus1text.color
|
||||
},
|
||||
medium: {
|
||||
backgroundColor: layout.colorstatus2.color,
|
||||
color: layout.colorstatus2text.color
|
||||
},
|
||||
normal: {
|
||||
backgroundColor: layout.colorstatus3.color,
|
||||
color: layout.colorstatus3text.color
|
||||
}
|
||||
}
|
||||
},
|
||||
symbolForNulls: layout.symbolfornulls,
|
||||
usePadding: layout.indentbool,
|
||||
useSeparatorColumns: dimensionCount === 1 ? false : layout.separatorcols
|
||||
}
|
||||
};
|
||||
|
||||
if (rowCount > lastRow && rowCount <= (maxLoops * 1000)) {
|
||||
const requestPage = [
|
||||
{
|
||||
qHeight: Math.min(1000, rowCount - lastRow),
|
||||
qLeft: 0,
|
||||
qTop: matrix.length,
|
||||
qWidth: 10 // should be # of columns
|
||||
}
|
||||
];
|
||||
component.backendApi.getData(requestPage).then(() => {
|
||||
component.paint($element, layout);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
return transformedProperties;
|
||||
}
|
||||
|
||||
export default initializeTransformed;
|
||||
@@ -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
131
src/masking.js
Normal 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;
|
||||
}
|
||||
1373
src/paint.js
1373
src/paint.js
File diff suppressed because it is too large
Load Diff
89
src/paint.jsx
Normal file
89
src/paint.jsx
Normal file
@@ -0,0 +1,89 @@
|
||||
import $ from 'jquery';
|
||||
import initializeStore from './store';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import HeadersTable from './headers-table/index.jsx';
|
||||
import DataTable from './data-table/index.jsx';
|
||||
|
||||
export default async function paint ($element, layout, component) {
|
||||
const state = await initializeStore({
|
||||
$element,
|
||||
component,
|
||||
layout
|
||||
});
|
||||
|
||||
const jsx = (
|
||||
<React.Fragment>
|
||||
<div className="kpi-table">
|
||||
<HeadersTable
|
||||
data={state.data}
|
||||
general={state.general}
|
||||
qlik={component}
|
||||
styling={state.styling}
|
||||
/>
|
||||
<DataTable
|
||||
data={state.data}
|
||||
general={state.general}
|
||||
qlik={component}
|
||||
renderData={false}
|
||||
styling={state.styling}
|
||||
/>
|
||||
</div>
|
||||
<div className="data-table">
|
||||
<HeadersTable
|
||||
data={state.data}
|
||||
general={state.general}
|
||||
qlik={component}
|
||||
styling={state.styling}
|
||||
/>
|
||||
<DataTable
|
||||
data={state.data}
|
||||
general={state.general}
|
||||
qlik={component}
|
||||
styling={state.styling}
|
||||
/>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
|
||||
ReactDOM.render(jsx, $element[0]);
|
||||
|
||||
|
||||
// TODO: skipped the following as they weren't blockers for letting react handle rendering,
|
||||
// they are however the only reason we still depend on jQuery and should be removed as part of unnecessary dependencies issue
|
||||
$(`[tid="${layout.qInfo.qId}"] .data-table .row-wrapper`).on('scroll', function () {
|
||||
$(`[tid="${layout.qInfo.qId}"] .kpi-table .row-wrapper`).scrollTop($(this).scrollTop());
|
||||
});
|
||||
|
||||
// freeze first column
|
||||
$(`[tid="${layout.qInfo.qId}"] .qv-object-content-container`).on('scroll', (t) => {
|
||||
$(`[tid="${layout.qInfo.qId}"] .kpi-table`).css('left', `${Math.round(t.target.scrollLeft)}px`);
|
||||
});
|
||||
|
||||
// TODO: fixing tooltips has a seperate issue, make sure to remove this as part of that issue
|
||||
$(`[tid="${layout.qInfo.qId}"] .header-wrapper th`).hover(function () {
|
||||
$(`[tid="${layout.qInfo.qId}"] .tooltip`).delay(500)
|
||||
.show(0);
|
||||
$(`[tid="${layout.qInfo.qId}"] .header-wrapper th`).children(`[tid="${layout.qInfo.qId}"] .tooltip`)
|
||||
.remove();
|
||||
|
||||
const element = $(this);
|
||||
const offset = element.offset();
|
||||
const toolTip = $('<div class="tooltip"></div>');
|
||||
|
||||
toolTip.css({
|
||||
left: offset.left,
|
||||
top: offset.top
|
||||
});
|
||||
|
||||
toolTip.text(element.text());
|
||||
$(`[tid="${layout.qInfo.qId}"] .header-wrapper th`).append(toolTip);
|
||||
}, () => {
|
||||
$(`[tid="${layout.qInfo.qId}"] .tooltip`).delay(0)
|
||||
.hide(0);
|
||||
});
|
||||
|
||||
// TODO: excel export is broken in most browsers, fixing it has an issue of it's own (leaving it disabled for now)
|
||||
// import { enableExcelExport } from './excel-export';
|
||||
// enableExcelExport(layout, html);
|
||||
}
|
||||
13
src/store.js
Normal file
13
src/store.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import initializeTransformed from './initialize-transformed';
|
||||
|
||||
async function initialize ({ $element, layout, component }) {
|
||||
const transformedProperties = await initializeTransformed({
|
||||
$element,
|
||||
component,
|
||||
layout
|
||||
});
|
||||
|
||||
return transformedProperties;
|
||||
}
|
||||
|
||||
export default initialize;
|
||||
109
src/style-builder.js
Normal file
109
src/style-builder.js
Normal file
@@ -0,0 +1,109 @@
|
||||
function StyleBuilder (styling) {
|
||||
const {
|
||||
colors,
|
||||
customCSV,
|
||||
options
|
||||
} = styling;
|
||||
let style = {
|
||||
fontSize: `${14 + options.fontSizeAdjustment}px`
|
||||
};
|
||||
let hasComments = false;
|
||||
let commentColor;
|
||||
let hasCustomFileStyle = false;
|
||||
|
||||
function applyStandardAttributes (rowNumber) {
|
||||
const isEven = rowNumber % 2 === 0;
|
||||
style.backgroundColor = isEven ? options.backgroundColor : options.backgroundColorOdd;
|
||||
style.color = options.color;
|
||||
style.fontSize = `${13 + options.fontSizeAdjustment}px`;
|
||||
}
|
||||
|
||||
function applyColor (color) {
|
||||
style.backgroundColor = color;
|
||||
commentColor = color;
|
||||
}
|
||||
|
||||
/* eslint-disable sort-keys*/
|
||||
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 + options.fontSizeAdjustment}px`; },
|
||||
'<medium>': () => { style.fontSize = `${14 + options.fontSizeAdjustment}px`; },
|
||||
'<small>': () => { style.fontSize = `${13 + options.fontSizeAdjustment}px`; },
|
||||
// text alignment
|
||||
'<center>': () => { style.textAlign = 'center'; }
|
||||
};
|
||||
/* eslint-enable sort-keys */
|
||||
|
||||
// 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) {
|
||||
for (let csvAttribute = 1; csvAttribute < customCSV.count; csvAttribute += 1) {
|
||||
let customAttribute = '';
|
||||
if (customCSV.basic.indexOf(columnText) < 0) {
|
||||
customAttribute = 'none';
|
||||
} else {
|
||||
hasCustomFileStyle = true;
|
||||
customAttribute = customCSV.full[customCSV.basic.indexOf(columnText)][csvAttribute];
|
||||
}
|
||||
applyProperty(customAttribute);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
applyCustomStyle,
|
||||
applyProperty,
|
||||
applyStandardAttributes,
|
||||
getCommentColor: () => commentColor,
|
||||
getStyle: () => style,
|
||||
hasComments: () => hasComments,
|
||||
hasCustomFileStyle: () => hasCustomFileStyle,
|
||||
hasFontSize: () => Boolean(style.fontSize),
|
||||
parseCustomFileStyle
|
||||
};
|
||||
}
|
||||
|
||||
export default StyleBuilder;
|
||||
52
src/utilities.js
Normal file
52
src/utilities.js
Normal file
@@ -0,0 +1,52 @@
|
||||
export function onlyUnique (value, index, self) {
|
||||
return self.indexOf(value) === index;
|
||||
}
|
||||
|
||||
export function distinctArray (array) {
|
||||
return array
|
||||
.map(entry => JSON.stringify(entry))
|
||||
.filter(onlyUnique)
|
||||
.map(entry => JSON.parse(entry));
|
||||
}
|
||||
|
||||
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;
|
||||
});
|
||||
}
|
||||
|
||||
export function injectSeparators (array, shouldHaveSeparator, suppliedOptions) {
|
||||
const defaultOptions = {
|
||||
atEvery: 1,
|
||||
separator: { isSeparator: true }
|
||||
};
|
||||
const options = {
|
||||
...defaultOptions,
|
||||
...suppliedOptions
|
||||
};
|
||||
|
||||
if (!shouldHaveSeparator) {
|
||||
return array;
|
||||
}
|
||||
return array.reduce((result, entry, index) => {
|
||||
result.push(entry);
|
||||
if (index < array.length - 1 && (index + 1) % options.atEvery === 0) {
|
||||
result.push(options.separator);
|
||||
}
|
||||
return result;
|
||||
}, []);
|
||||
}
|
||||
@@ -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'
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user