diff --git a/.gitignore b/.gitignore index 034d69f6d..f1d13a5f4 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,8 @@ tmp/ build.number build/ dist +:wq *.iml .vscode .idea +.back diff --git a/Gruntfile.js b/Gruntfile.js index bd73fdbbd..399e7958a 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -58,8 +58,9 @@ module.exports = function (grunt) { } }, options: { - jshintrc: '.jshintrc', - reporterOutput: '' + jshintrc:'.jshintrc', + reporterOutput: '', + force: true, } }, htmlmin:{ @@ -229,7 +230,8 @@ module.exports = function (grunt) { 'jquery.flot.pie', 'angular-sanitize', 'angular-dragdrop', - 'd3' + 'd3', + 'echarts', ] } ]; @@ -266,7 +268,7 @@ module.exports = function (grunt) { 'requirejs:build', 'clean:temp', 'build:write_revision', - 'uglify:dest' + 'uglify:dest', ]); // run a string replacement on the require config, using the latest revision number as the cache buster diff --git a/bower.json b/bower.json index 24ee4686b..d2040c79e 100644 --- a/bower.json +++ b/bower.json @@ -4,11 +4,7 @@ "homepage": "https://github.com/LucidWorks/banana/wiki", "license": "Apache License", "dependencies": { - "angular": "1.0.8", - "angular-loader": "1.0.8", - "angular-mocks": "1.0.8", - "angular-sanitize": "1.0.8", - "angular-strap": "0.7.5", + "angular": "1.6.4", "bootstrap": "2.3.2", "d3": "~3.4.11", "jquery": "1.12.1", @@ -17,10 +13,20 @@ "requirejs": "2.1.8", "modernizr": "2.6.1", "moment": "2.1.0", - "underscore": "1.5.1" + "underscore": "1.5.1", + "angular-loader": "^1.6.4", + "angular-mocks": "^1.6.4", + "angular-sanitize": "^1.6.4", + "angular-strap": "0.7.5", + "angular-material": "^1.1.4", + "angular-route": "^1.6.4", + "angular-smart-table": "^2.1.8", + "angular-dragdrop": "^1.0.13", + "jspdf": "^1.3.4", + "html2canvas": "^0.4.1" }, "resolutions": { - "angular": "1.0.8", + "angular": "1.6.4", "jquery": "1.12.1", "bootstrap": "2.3.2" } diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..46c192c29 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,5960 @@ +{ + "name": "banana-fusion", + "version": "1.6.17", + "lockfileVersion": 1, + "dependencies": { + "@types/node": { + "version": "https://registry.npmjs.org/@types/node/-/node-6.0.78.tgz", + "integrity": "sha1-XUo/V5wVJOAe4hv0dOb7oJGY9HA=", + "dev": true + }, + "@types/q": { + "version": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", + "integrity": "sha1-vShOV8hPEyXacCur/IKlMoGQwMU=", + "dev": true + }, + "@types/selenium-webdriver": { + "version": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-2.53.42.tgz", + "integrity": "sha1-dMt3+2BS7a/yqJhN2v2I1BnyXKw=", + "dev": true + }, + "abbrev": { + "version": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz", + "integrity": "sha1-0FVMIlZjbi9W58LlrRg/hZQo2B8=", + "dev": true + }, + "accepts": { + "version": "https://registry.npmjs.org/accepts/-/accepts-1.2.13.tgz", + "integrity": "sha1-5fHzkoxtlf2WVYw27D2dDeSm7Oo=", + "dev": true + }, + "active-x-obfuscator": { + "version": "https://registry.npmjs.org/active-x-obfuscator/-/active-x-obfuscator-0.0.1.tgz", + "integrity": "sha1-CJuJs3FF/x2ex0r2UwvlUmyuHxo=", + "dev": true + }, + "adm-zip": { + "version": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.7.tgz", + "integrity": "sha1-hgbCy/HEJs6MjsABdER/1Jtur8E=", + "dev": true + }, + "agent-base": { + "version": "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz", + "integrity": "sha1-1t4Q1a9hMtW9aSQn1G/FOFOQlMc=", + "dev": true, + "dependencies": { + "semver": { + "version": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz", + "integrity": "sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=", + "dev": true + } + } + }, + "ajv": { + "version": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "dev": true + }, + "align-text": { + "version": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "dev": true + }, + "alter": { + "version": "https://registry.npmjs.org/alter/-/alter-0.2.0.tgz", + "integrity": "sha1-x1iICGF1cgNKrmJICvJrHU0cs80=", + "dev": true + }, + "amdefine": { + "version": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true + }, + "ansi-regex": { + "version": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "anymatch": { + "version": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.0.tgz", + "integrity": "sha1-o+Uvo5FoyCX/V7AkgSbOWo/5VQc=", + "dev": true + }, + "archiver": { + "version": "https://registry.npmjs.org/archiver/-/archiver-0.4.10.tgz", + "integrity": "sha1-3w/qyPHRKV5ezrOiBVWQctIfR0c=", + "dev": true + }, + "argparse": { + "version": "https://registry.npmjs.org/argparse/-/argparse-0.1.16.tgz", + "integrity": "sha1-z9AeD7uj1srtBJ+9dY1A9lGW9Xw=", + "dev": true, + "dependencies": { + "underscore.string": { + "version": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz", + "integrity": "sha1-jN2PusTi0uoefi6Al8QvRCKA+Fs=", + "dev": true + } + } + }, + "arr-diff": { + "version": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true + }, + "arr-flatten": { + "version": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.0.3.tgz", + "integrity": "sha1-onTthawIhJtr14R8RYB0XcUa37E=", + "dev": true + }, + "array-union": { + "version": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true + }, + "array-uniq": { + "version": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array-unique": { + "version": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true + }, + "arrify": { + "version": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asn1": { + "version": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", + "dev": true + }, + "assert-plus": { + "version": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", + "dev": true + }, + "astral": { + "version": "https://registry.npmjs.org/astral/-/astral-0.1.0.tgz", + "integrity": "sha1-5uPGTv2gg+xMFEA6pIAx/8/ChcU=", + "dev": true + }, + "astral-angular-annotate": { + "version": "https://registry.npmjs.org/astral-angular-annotate/-/astral-angular-annotate-0.0.2.tgz", + "integrity": "sha1-I4lNc0gYhAg0zTVzpU2uNWYyoYk=", + "dev": true + }, + "astral-pass": { + "version": "https://registry.npmjs.org/astral-pass/-/astral-pass-0.1.0.tgz", + "integrity": "sha1-fnhRB3oh5B2YGRkIolhGfs0w7ug=", + "dev": true + }, + "async": { + "version": "https://registry.npmjs.org/async/-/async-0.1.22.tgz", + "integrity": "sha1-D8GqoIig4+8Ovi2IMbqw3PiEUGE=", + "dev": true + }, + "async-each": { + "version": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", + "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "dev": true + }, + "asynckit": { + "version": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "aws-sign": { + "version": "https://registry.npmjs.org/aws-sign/-/aws-sign-0.2.0.tgz", + "integrity": "sha1-xVAThWyBlOyFSgy+yQqrWgTOOsU=", + "dev": true + }, + "aws-sign2": { + "version": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", + "dev": true + }, + "aws4": { + "version": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", + "dev": true + }, + "balanced-match": { + "version": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base64-url": { + "version": "https://registry.npmjs.org/base64-url/-/base64-url-1.2.1.tgz", + "integrity": "sha1-GZ/WYXAqDnt9yubgaYuwicUvbXg=", + "dev": true + }, + "base64id": { + "version": "https://registry.npmjs.org/base64id/-/base64id-0.1.0.tgz", + "integrity": "sha1-As4P3u4M709ACA4ec+g08LG/zj8=", + "dev": true + }, + "basic-auth": { + "version": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.0.4.tgz", + "integrity": "sha1-Awk1sB3nyblKgksp8/zLdQ06UpA=", + "dev": true + }, + "basic-auth-connect": { + "version": "https://registry.npmjs.org/basic-auth-connect/-/basic-auth-connect-1.0.0.tgz", + "integrity": "sha1-/bC0OWLKe0BFanwrtI/hc9otISI=", + "dev": true + }, + "batch": { + "version": "https://registry.npmjs.org/batch/-/batch-0.5.3.tgz", + "integrity": "sha1-PzQU84AyF0O/wQQvmoP/HVgk1GQ=", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "dev": true, + "optional": true + }, + "binary-extensions": { + "version": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.8.0.tgz", + "integrity": "sha1-SOyNFt9Dd+rl+liEaCSAr02Vx3Q=", + "dev": true + }, + "bind-obj-methods": { + "version": "https://registry.npmjs.org/bind-obj-methods/-/bind-obj-methods-1.0.0.tgz", + "integrity": "sha1-T1l5ysFXk633DkiBYeRj4gnKUJw=", + "dev": true + }, + "bl": { + "version": "https://registry.npmjs.org/bl/-/bl-1.0.3.tgz", + "integrity": "sha1-/FQhoo/UImA2w7OJGmaiW8ZNIm4=", + "dev": true, + "dependencies": { + "isarray": { + "version": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "dev": true + } + } + }, + "block-stream": { + "version": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "dev": true + }, + "blocking-proxy": { + "version": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-0.0.4.tgz", + "integrity": "sha1-SQFnMqw46NU6LH3NUCUgqg5Y4EQ=", + "dev": true, + "dependencies": { + "minimist": { + "version": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "bluebird": { + "version": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", + "integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw=", + "dev": true + }, + "body-parser": { + "version": "https://registry.npmjs.org/body-parser/-/body-parser-1.13.3.tgz", + "integrity": "sha1-wIzzMMM1jhUQFqBXRvE/ApyX+pc=", + "dev": true, + "dependencies": { + "bytes": { + "version": "https://registry.npmjs.org/bytes/-/bytes-2.1.0.tgz", + "integrity": "sha1-rJPEEOL/ycx89LRks4KJBn9eR7Q=", + "dev": true + }, + "debug": { + "version": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true + }, + "iconv-lite": { + "version": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.11.tgz", + "integrity": "sha1-LstC/SlHRJIiCaLnxATayHk9it4=", + "dev": true + }, + "ms": { + "version": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true + }, + "qs": { + "version": "https://registry.npmjs.org/qs/-/qs-4.0.0.tgz", + "integrity": "sha1-wx2bdOwn33XlQ6hseHKO2NRiNgc=", + "dev": true + } + } + }, + "boom": { + "version": "https://registry.npmjs.org/boom/-/boom-0.3.8.tgz", + "integrity": "sha1-yM2wQUNZEnQWKMBE7Mcy0dF8Ceo=", + "dev": true + }, + "bower": { + "version": "https://registry.npmjs.org/bower/-/bower-1.8.0.tgz", + "integrity": "sha1-Vdvr7wrZFVOC2enT5JfBNyNFtEo=", + "dev": true + }, + "brace-expansion": { + "version": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "dev": true + }, + "braces": { + "version": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true + }, + "buffer-crc32": { + "version": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.1.tgz", + "integrity": "sha1-vj5TgvwCttYySVasGvmKqYsIU0w=", + "dev": true + }, + "bytes": { + "version": "https://registry.npmjs.org/bytes/-/bytes-0.2.0.tgz", + "integrity": "sha1-qtM+wU49wsp06OfUUfm6BTrU96A=", + "dev": true + }, + "camelcase": { + "version": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true + }, + "caseless": { + "version": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", + "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", + "dev": true + }, + "center-align": { + "version": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "dev": true + }, + "chalk": { + "version": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true + }, + "character-parser": { + "version": "https://registry.npmjs.org/character-parser/-/character-parser-1.0.2.tgz", + "integrity": "sha1-VThNavz4xrndSD6DR2RqeQ5FRec=", + "dev": true + }, + "chokidar": { + "version": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "dev": true, + "dependencies": { + "graceful-fs": { + "version": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true + }, + "isarray": { + "version": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "minimatch": { + "version": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "dev": true + }, + "readable-stream": { + "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.2.tgz", + "integrity": "sha1-WgTfBeT1f+Pw3Gj90R3FyXx+b00=", + "dev": true + }, + "readdirp": { + "version": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", + "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", + "dev": true + }, + "string_decoder": { + "version": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", + "dev": true + } + } + }, + "clean-css": { + "version": "https://registry.npmjs.org/clean-css/-/clean-css-1.1.7.tgz", + "integrity": "sha1-YB75z3ZCuYLLM+/JSIpkRMmGaG4=", + "dev": true + }, + "clean-yaml-object": { + "version": "https://registry.npmjs.org/clean-yaml-object/-/clean-yaml-object-0.1.0.tgz", + "integrity": "sha1-Y/sRDcLOGoTcIfbZM0h20BCui2g=", + "dev": true + }, + "cli": { + "version": "https://registry.npmjs.org/cli/-/cli-0.4.5.tgz", + "integrity": "sha1-ePlIXNFhtWbppsctcXDEJw6B22E=", + "dev": true + }, + "cliui": { + "version": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "dependencies": { + "wordwrap": { + "version": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true + } + } + }, + "clone": { + "version": "https://registry.npmjs.org/clone/-/clone-0.1.19.tgz", + "integrity": "sha1-YT+2hjmyaklKxTJT4Vsaa9iK2oU=", + "dev": true + }, + "co": { + "version": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "coffee-script": { + "version": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.3.3.tgz", + "integrity": "sha1-FQ1rTLUiiUNp7+1qIQHCC8f0pPQ=", + "dev": true + }, + "color-support": { + "version": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha1-k4NDeaHMmgxh+C9S8NBDIiUb1aI=", + "dev": true + }, + "colors": { + "version": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", + "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=", + "dev": true + }, + "combined-stream": { + "version": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz", + "integrity": "sha1-ATfmV7qlp1QcV6w3rF/AfXO03B8=", + "dev": true + }, + "commander": { + "version": "https://registry.npmjs.org/commander/-/commander-2.0.0.tgz", + "integrity": "sha1-0bhvkB+LZL2UG96tr5JFMDk76Sg=", + "dev": true + }, + "compressible": { + "version": "https://registry.npmjs.org/compressible/-/compressible-2.0.10.tgz", + "integrity": "sha1-/tocf3YXkScyspv4zyYlKiC57s0=", + "dev": true + }, + "compression": { + "version": "https://registry.npmjs.org/compression/-/compression-1.5.2.tgz", + "integrity": "sha1-sDuNhub4rSloPLqN+R3cb/x3s5U=", + "dev": true, + "dependencies": { + "bytes": { + "version": "https://registry.npmjs.org/bytes/-/bytes-2.1.0.tgz", + "integrity": "sha1-rJPEEOL/ycx89LRks4KJBn9eR7Q=", + "dev": true + }, + "debug": { + "version": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true + }, + "ms": { + "version": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true + } + } + }, + "concat-map": { + "version": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.0.tgz", + "integrity": "sha1-U/fUPFHF5D+ByP3QMyHGMb5o1hE=", + "dev": true, + "dependencies": { + "isarray": { + "version": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "dev": true + } + } + }, + "connect": { + "version": "https://registry.npmjs.org/connect/-/connect-2.7.11.tgz", + "integrity": "sha1-9WHV7vcLjXGcOX9yTTS6QGXHej4=", + "dev": true + }, + "connect-timeout": { + "version": "https://registry.npmjs.org/connect-timeout/-/connect-timeout-1.6.2.tgz", + "integrity": "sha1-3ppexh4zoStu2qt7XwYumMWZuI4=", + "dev": true, + "dependencies": { + "debug": { + "version": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true + }, + "ms": { + "version": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true + } + } + }, + "console-browserify": { + "version": "https://registry.npmjs.org/console-browserify/-/console-browserify-0.1.6.tgz", + "integrity": "sha1-0SijwLuINQ61YmxufHGm8P1ImDw=", + "dev": true + }, + "content-type": { + "version": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz", + "integrity": "sha1-t9ETrueo3Se9IRM8TcJSnfFyHu0=", + "dev": true + }, + "convert-source-map": { + "version": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-0.4.1.tgz", + "integrity": "sha1-+RmgCZ/jH4D8Wh0OswMWGzlAcMc=", + "dev": true + }, + "cookie": { + "version": "https://registry.npmjs.org/cookie/-/cookie-0.0.5.tgz", + "integrity": "sha1-+az521frdWjJ/MWWJWt7si4wfIE=", + "dev": true + }, + "cookie-jar": { + "version": "https://registry.npmjs.org/cookie-jar/-/cookie-jar-0.2.0.tgz", + "integrity": "sha1-ZOzAasl423leS1KQy+SLo3gUAPo=", + "dev": true + }, + "cookie-parser": { + "version": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.3.5.tgz", + "integrity": "sha1-nXVVcPtdF4kHcSJ6AjFNm+fPg1Y=", + "dev": true, + "dependencies": { + "cookie": { + "version": "https://registry.npmjs.org/cookie/-/cookie-0.1.3.tgz", + "integrity": "sha1-5zSlwUF/zkctWu+Cw4HKu2TRpDU=", + "dev": true + }, + "cookie-signature": { + "version": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true + } + } + }, + "cookie-signature": { + "version": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.1.tgz", + "integrity": "sha1-ROByFIrwHm6OJK+/EmkNaK5pjss=", + "dev": true + }, + "core-util-is": { + "version": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "coveralls": { + "version": "https://registry.npmjs.org/coveralls/-/coveralls-2.13.1.tgz", + "integrity": "sha1-1wu5rMGDXsTwY/+drFQjwXsR8Xg=", + "dev": true, + "dependencies": { + "argparse": { + "version": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", + "dev": true + }, + "boom": { + "version": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "dev": true + }, + "combined-stream": { + "version": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "dev": true + }, + "cryptiles": { + "version": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "dev": true + }, + "delayed-stream": { + "version": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "esprima": { + "version": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "dev": true + }, + "forever-agent": { + "version": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", + "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "dev": true + }, + "hawk": { + "version": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "dev": true + }, + "hoek": { + "version": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", + "dev": true + }, + "js-yaml": { + "version": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.6.1.tgz", + "integrity": "sha1-bl/mfYsgXOTSL60Ft3geja3MSzA=", + "dev": true + }, + "json-stringify-safe": { + "version": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "minimist": { + "version": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "oauth-sign": { + "version": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "dev": true + }, + "qs": { + "version": "https://registry.npmjs.org/qs/-/qs-6.3.2.tgz", + "integrity": "sha1-51vV9uJoEioqDgvaYwslUMFmUCw=", + "dev": true + }, + "request": { + "version": "https://registry.npmjs.org/request/-/request-2.79.0.tgz", + "integrity": "sha1-Tf5b9r6LjNw3/Pk+BLZVd3InEN4=", + "dev": true + }, + "sntp": { + "version": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "dev": true + }, + "tough-cookie": { + "version": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", + "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", + "dev": true + }, + "tunnel-agent": { + "version": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", + "dev": true + }, + "uuid": { + "version": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", + "integrity": "sha1-PdPT55Crwk17DToDT/q6vijrvAQ=", + "dev": true + } + } + }, + "crc": { + "version": "https://registry.npmjs.org/crc/-/crc-3.3.0.tgz", + "integrity": "sha1-+mIuG8OIvyVzCQgta2UgDOZwkLo=", + "dev": true + }, + "cross-spawn": { + "version": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", + "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", + "dev": true, + "dependencies": { + "lru-cache": { + "version": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", + "integrity": "sha1-Yi4y6CSItJJ5EUpPns9F581rulU=", + "dev": true + }, + "which": { + "version": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", + "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", + "dev": true + } + } + }, + "cryptiles": { + "version": "https://registry.npmjs.org/cryptiles/-/cryptiles-0.1.3.tgz", + "integrity": "sha1-GlVnNPBtJLo0hirpy55wmjr7/xw=", + "dev": true + }, + "csrf": { + "version": "https://registry.npmjs.org/csrf/-/csrf-3.0.6.tgz", + "integrity": "sha1-thEg3c7q/JHnbtUxO7XAsmZ7cQo=", + "dev": true + }, + "css": { + "version": "https://registry.npmjs.org/css/-/css-1.0.8.tgz", + "integrity": "sha1-k4aBHKgrzMnuf7WnMrHioxfIo+c=", + "dev": true + }, + "css-parse": { + "version": "https://registry.npmjs.org/css-parse/-/css-parse-1.0.4.tgz", + "integrity": "sha1-OLBQP7+dqfVOnB29pg4UXHcRe90=", + "dev": true + }, + "css-stringify": { + "version": "https://registry.npmjs.org/css-stringify/-/css-stringify-1.0.5.tgz", + "integrity": "sha1-sNBClG2ylTu50pKQCmy19tASIDE=", + "dev": true + }, + "csslint": { + "version": "https://registry.npmjs.org/csslint/-/csslint-0.9.10.tgz", + "integrity": "sha1-xBuptrn+x3vKhxEuces6Ig71m8Q=", + "dev": true + }, + "cssom": { + "version": "https://registry.npmjs.org/cssom/-/cssom-0.2.5.tgz", + "integrity": "sha1-JoJwm1kC5yEt9SkRb/eIzVslSJQ=", + "dev": true + }, + "csurf": { + "version": "https://registry.npmjs.org/csurf/-/csurf-1.8.3.tgz", + "integrity": "sha1-I/KhO/HY/OHQyZZYg5RELLqGpWo=", + "dev": true, + "dependencies": { + "cookie": { + "version": "https://registry.npmjs.org/cookie/-/cookie-0.1.3.tgz", + "integrity": "sha1-5zSlwUF/zkctWu+Cw4HKu2TRpDU=", + "dev": true + }, + "cookie-signature": { + "version": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true + } + } + }, + "ctype": { + "version": "https://registry.npmjs.org/ctype/-/ctype-0.5.2.tgz", + "integrity": "sha1-/oCR1Gijc6Cwyf+Lv7NCXACXOh0=", + "dev": true + }, + "dashdash": { + "version": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "dependencies": { + "assert-plus": { + "version": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "date-now": { + "version": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", + "dev": true + }, + "dateformat": { + "version": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.2-1.2.3.tgz", + "integrity": "sha1-sCIMAt6YYXQztyhRz0fePfLNvuk=", + "dev": true + }, + "debug": { + "version": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", + "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", + "dev": true + }, + "decamelize": { + "version": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "deep-equal": { + "version": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", + "dev": true + }, + "del": { + "version": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "dev": true + }, + "delayed-stream": { + "version": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz", + "integrity": "sha1-1LH0OpPoKW3+AmlPRoC8N6MTxz8=", + "dev": true + }, + "depd": { + "version": "https://registry.npmjs.org/depd/-/depd-1.0.1.tgz", + "integrity": "sha1-gK7GTJ1tl+ZcwqnKqTwKpqv3Oqo=", + "dev": true + }, + "destroy": { + "version": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "dev": true + }, + "di": { + "version": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", + "dev": true + }, + "diff": { + "version": "https://registry.npmjs.org/diff/-/diff-1.0.2.tgz", + "integrity": "sha1-Suc/Gu6Nb89ITxoc53zmUdm38Mk=", + "dev": true + }, + "dom-serializer": { + "version": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", + "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", + "dev": true, + "dependencies": { + "domelementtype": { + "version": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", + "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", + "dev": true + }, + "entities": { + "version": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", + "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=", + "dev": true + } + } + }, + "domelementtype": { + "version": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", + "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=", + "dev": true + }, + "domhandler": { + "version": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", + "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", + "dev": true + }, + "domutils": { + "version": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "dev": true + }, + "duplexer": { + "version": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", + "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", + "dev": true + }, + "ecc-jsbn": { + "version": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "dev": true, + "optional": true + }, + "echarts": { + "version": "https://registry.npmjs.org/echarts/-/echarts-3.6.2.tgz", + "integrity": "sha1-hilUyLWBC/+HpIsN4EFu2MS7HDY=" + }, + "echarts-gl": { + "version": "https://registry.npmjs.org/echarts-gl/-/echarts-gl-1.0.0-alpha.9.tgz", + "integrity": "sha1-zzhZzDz9s9qkk5We9JvMwX2cErM=" + }, + "echarts-liquidfill": { + "version": "https://registry.npmjs.org/echarts-liquidfill/-/echarts-liquidfill-1.0.5.tgz", + "integrity": "sha1-u9YxRvtpa6zQZAi08rVmszKpSP4=" + }, + "echarts-wordcloud": { + "version": "https://registry.npmjs.org/echarts-wordcloud/-/echarts-wordcloud-1.1.0.tgz", + "integrity": "sha1-zDCLxYPDm86TyeSgvZ85xjvi3fc=" + }, + "ecstatic": { + "version": "https://registry.npmjs.org/ecstatic/-/ecstatic-0.4.13.tgz", + "integrity": "sha1-nLbq/+IRuchO+z9VPN4sMAJxeyk=", + "dev": true + }, + "ee-first": { + "version": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "ent": { + "version": "https://registry.npmjs.org/ent/-/ent-0.0.7.tgz", + "integrity": "sha1-g11Of556jUkhxpLpAQ7JdtpemUk=", + "dev": true + }, + "entities": { + "version": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", + "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=", + "dev": true + }, + "errorhandler": { + "version": "https://registry.npmjs.org/errorhandler/-/errorhandler-1.4.3.tgz", + "integrity": "sha1-t7cO2PNZ6duICS8tIMD4MUIK2D8=", + "dev": true, + "dependencies": { + "accepts": { + "version": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", + "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=", + "dev": true + }, + "negotiator": { + "version": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", + "dev": true + } + } + }, + "escape-html": { + "version": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "escape-string-regexp": { + "version": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "escodegen": { + "version": "https://registry.npmjs.org/escodegen/-/escodegen-0.0.28.tgz", + "integrity": "sha1-Dk/xcV8yh3XWyrUaxEpAbNer/9M=", + "dev": true + }, + "esprima": { + "version": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", + "integrity": "sha1-n1V+CPw7TSbs6d00+Pv0drYlha0=", + "dev": true + }, + "estraverse": { + "version": "https://registry.npmjs.org/estraverse/-/estraverse-1.3.2.tgz", + "integrity": "sha1-N8K4k+8T1yPydth41g2FNRUqbEI=", + "dev": true + }, + "etag": { + "version": "https://registry.npmjs.org/etag/-/etag-1.7.0.tgz", + "integrity": "sha1-A9MLX2fdbmMtKUXTDWZScxo01dg=", + "dev": true + }, + "eventemitter2": { + "version": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", + "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=", + "dev": true + }, + "events-to-array": { + "version": "https://registry.npmjs.org/events-to-array/-/events-to-array-1.1.2.tgz", + "integrity": "sha1-LUH1Y+H+QA7Uli/hpNXGp1Od9/Y=", + "dev": true + }, + "exit": { + "version": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "expand-brackets": { + "version": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true + }, + "expand-range": { + "version": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "dev": true + }, + "express": { + "version": "https://registry.npmjs.org/express/-/express-3.1.2.tgz", + "integrity": "sha1-UqAsjbjyK7+g10eNhHzUUWH5hfc=", + "dev": true, + "dependencies": { + "commander": { + "version": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", + "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", + "dev": true + }, + "connect": { + "version": "https://registry.npmjs.org/connect/-/connect-2.7.5.tgz", + "integrity": "sha1-E5ERtLA/BTOlJJJ6iKZGrkZ7LAI=", + "dev": true, + "dependencies": { + "buffer-crc32": { + "version": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.1.1.tgz", + "integrity": "sha1-fhENyZU5CKt8MqzccMn5RbHLxSY=", + "dev": true + } + } + }, + "cookie-signature": { + "version": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.0.tgz", + "integrity": "sha1-AETzMqxiPfhRyRTojqzFfwyXBP4=", + "dev": true + }, + "formidable": { + "version": "https://registry.npmjs.org/formidable/-/formidable-1.0.11.tgz", + "integrity": "sha1-aPYzJaA15kS297s9ESQ7l2HeGzA=", + "dev": true + }, + "mime": { + "version": "https://registry.npmjs.org/mime/-/mime-1.2.6.tgz", + "integrity": "sha1-sfhsdowCX6h7SAdfFwnyiuryA2U=", + "dev": true + }, + "mkdirp": { + "version": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", + "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=", + "dev": true + }, + "qs": { + "version": "https://registry.npmjs.org/qs/-/qs-0.5.1.tgz", + "integrity": "sha1-n2v12axsdjhOldNtFbSJgOXkrdA=", + "dev": true + }, + "send": { + "version": "https://registry.npmjs.org/send/-/send-0.1.0.tgz", + "integrity": "sha1-z7COvTzsm3/Bo32f+eh1qXHPRkA=", + "dev": true + } + } + }, + "express-session": { + "version": "https://registry.npmjs.org/express-session/-/express-session-1.11.3.tgz", + "integrity": "sha1-XMmPP1/4Ttg1+Ry/CqvQxxB0AK8=", + "dev": true, + "dependencies": { + "cookie": { + "version": "https://registry.npmjs.org/cookie/-/cookie-0.1.3.tgz", + "integrity": "sha1-5zSlwUF/zkctWu+Cw4HKu2TRpDU=", + "dev": true + }, + "cookie-signature": { + "version": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true + }, + "debug": { + "version": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true + }, + "ms": { + "version": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true + }, + "uid-safe": { + "version": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.0.0.tgz", + "integrity": "sha1-p/PGymSh9qXQTsDvPkw9U2cxcTc=", + "dev": true + } + } + }, + "extend": { + "version": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", + "dev": true + }, + "extglob": { + "version": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true + }, + "extract-zip": { + "version": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.5.0.tgz", + "integrity": "sha1-ksz22B73Cp+kwXRxFMzvbYaIpsQ=", + "dev": true, + "dependencies": { + "debug": { + "version": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", + "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=", + "dev": true + }, + "mkdirp": { + "version": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz", + "integrity": "sha1-HXMHam35hs2TROFecfzAWkyavxI=", + "dev": true + } + } + }, + "extsprintf": { + "version": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz", + "integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=", + "dev": true + }, + "faye-websocket": { + "version": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.4.4.tgz", + "integrity": "sha1-wUxbO/FNdBf/v9mQwKdJXNnzN7w=", + "dev": true + }, + "fd-slicer": { + "version": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", + "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", + "dev": true + }, + "figures": { + "version": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true + }, + "filename-regex": { + "version": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "dev": true + }, + "fileset": { + "version": "https://registry.npmjs.org/fileset/-/fileset-0.1.8.tgz", + "integrity": "sha1-UGuRqTluqn4y+0KoQHfHoMc2t0E=", + "dev": true + }, + "filesize": { + "version": "https://registry.npmjs.org/filesize/-/filesize-1.7.9.tgz", + "integrity": "sha1-sKh6I2upksA/9o0mSgkgV+FEx3Q=", + "dev": true + }, + "fill-range": { + "version": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", + "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", + "dev": true + }, + "finalhandler": { + "version": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.4.0.tgz", + "integrity": "sha1-llpS2ejQXSuFdUhUH7ibU6JJfZs=", + "dev": true, + "dependencies": { + "debug": { + "version": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true + }, + "escape-html": { + "version": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.2.tgz", + "integrity": "sha1-130y+pjjjC9BroXpJ44ODmuhAiw=", + "dev": true + }, + "ms": { + "version": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true + } + } + }, + "findup-sync": { + "version": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.1.3.tgz", + "integrity": "sha1-fz56l7gjksZTvwZYm9hRkOk8NoM=", + "dev": true, + "dependencies": { + "glob": { + "version": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", + "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", + "dev": true + }, + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", + "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", + "dev": true + }, + "minimatch": { + "version": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", + "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", + "dev": true + } + } + }, + "for-in": { + "version": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true + }, + "foreground-child": { + "version": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", + "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=", + "dev": true + }, + "forever-agent": { + "version": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.2.0.tgz", + "integrity": "sha1-4cJcetROCcOPIzh2x2/MJP+EOx8=", + "dev": true + }, + "form-data": { + "version": "https://registry.npmjs.org/form-data/-/form-data-0.0.10.tgz", + "integrity": "sha1-2zRaU3jYau6x7V1VO4aawZLS9e0=", + "dev": true, + "dependencies": { + "async": { + "version": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", + "dev": true + } + } + }, + "formidable": { + "version": "https://registry.npmjs.org/formidable/-/formidable-1.0.14.tgz", + "integrity": "sha1-Kz9MQRy7X91pXESEPiojUUpDIxo=", + "dev": true + }, + "fresh": { + "version": "https://registry.npmjs.org/fresh/-/fresh-0.1.0.tgz", + "integrity": "sha1-A+SwF4Qk5MLV0ZpU2IFM3JeTSFA=", + "dev": true + }, + "fs-exists-cached": { + "version": "https://registry.npmjs.org/fs-exists-cached/-/fs-exists-cached-1.0.0.tgz", + "integrity": "sha1-zyVVTKBQ3EmuZla0HeQiWJidy84=", + "dev": true + }, + "fs-extra": { + "version": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz", + "integrity": "sha1-muH92UiXeY7at20JGM9C0MMYT6k=", + "dev": true, + "dependencies": { + "graceful-fs": { + "version": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true + } + } + }, + "fs.realpath": { + "version": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.2.tgz", + "integrity": "sha512-Sn44E5wQW4bTHXvQmvSHwqbuiXtduD6Rrjm2ZtUEGbyrig+nUH3t/QD4M4/ZXViY556TBpRgZkHLDx3JxPwxiw==", + "dev": true, + "optional": true, + "dependencies": { + "abbrev": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "ajv": { + "version": "4.11.8", + "bundled": true, + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "aproba": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "bundled": true, + "dev": true, + "optional": true + }, + "asn1": { + "version": "0.2.3", + "bundled": true, + "dev": true, + "optional": true + }, + "assert-plus": { + "version": "0.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "asynckit": { + "version": "0.4.0", + "bundled": true, + "dev": true, + "optional": true + }, + "aws-sign2": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "aws4": { + "version": "1.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "balanced-match": { + "version": "0.4.2", + "bundled": true, + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "block-stream": { + "version": "0.0.9", + "bundled": true, + "dev": true + }, + "boom": { + "version": "2.10.1", + "bundled": true, + "dev": true + }, + "brace-expansion": { + "version": "1.1.7", + "bundled": true, + "dev": true + }, + "buffer-shims": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "caseless": { + "version": "0.12.0", + "bundled": true, + "dev": true, + "optional": true + }, + "co": { + "version": "4.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "combined-stream": { + "version": "1.0.5", + "bundled": true, + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "cryptiles": { + "version": "2.0.5", + "bundled": true, + "dev": true, + "optional": true + }, + "dashdash": { + "version": "1.14.1", + "bundled": true, + "dev": true, + "optional": true, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "debug": { + "version": "2.6.8", + "bundled": true, + "dev": true, + "optional": true + }, + "deep-extend": { + "version": "0.4.2", + "bundled": true, + "dev": true, + "optional": true + }, + "delayed-stream": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "ecc-jsbn": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "extend": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "extsprintf": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "bundled": true, + "dev": true, + "optional": true + }, + "form-data": { + "version": "2.1.4", + "bundled": true, + "dev": true, + "optional": true + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "fstream": { + "version": "1.0.11", + "bundled": true, + "dev": true + }, + "fstream-ignore": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true + }, + "getpass": { + "version": "0.1.7", + "bundled": true, + "dev": true, + "optional": true, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "dev": true + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true, + "dev": true + }, + "har-schema": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "optional": true + }, + "har-validator": { + "version": "4.2.1", + "bundled": true, + "dev": true, + "optional": true + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "hawk": { + "version": "3.1.3", + "bundled": true, + "dev": true, + "optional": true + }, + "hoek": { + "version": "2.16.3", + "bundled": true, + "dev": true + }, + "http-signature": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true + }, + "ini": { + "version": "1.3.4", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "isstream": { + "version": "0.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "jodid25519": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "jsbn": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "json-schema": { + "version": "0.2.3", + "bundled": true, + "dev": true, + "optional": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "jsonify": { + "version": "0.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "jsprim": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "mime-db": { + "version": "1.27.0", + "bundled": true, + "dev": true + }, + "mime-types": { + "version": "2.1.15", + "bundled": true, + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true + }, + "ms": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "nan": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.6.2.tgz", + "integrity": "sha1-5P805slf37WuzAjeZZb0NgWn20U=", + "dev": true, + "optional": true + }, + "node-pre-gyp": { + "version": "0.6.36", + "bundled": true, + "dev": true, + "optional": true + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "npmlog": { + "version": "4.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "oauth-sign": { + "version": "0.8.2", + "bundled": true, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.4", + "bundled": true, + "dev": true, + "optional": true + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "performance-now": { + "version": "0.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "1.0.7", + "bundled": true, + "dev": true + }, + "punycode": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "optional": true + }, + "qs": { + "version": "6.4.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.2.9", + "bundled": true, + "dev": true + }, + "request": { + "version": "2.81.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rimraf": { + "version": "2.6.1", + "bundled": true, + "dev": true + }, + "safe-buffer": { + "version": "5.0.1", + "bundled": true, + "dev": true + }, + "semver": { + "version": "5.3.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sntp": { + "version": "1.0.9", + "bundled": true, + "dev": true, + "optional": true + }, + "sshpk": { + "version": "1.13.0", + "bundled": true, + "dev": true, + "optional": true, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "string_decoder": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "stringstream": { + "version": "0.0.5", + "bundled": true, + "dev": true, + "optional": true + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "2.2.1", + "bundled": true, + "dev": true + }, + "tar-pack": { + "version": "3.4.0", + "bundled": true, + "dev": true, + "optional": true + }, + "tough-cookie": { + "version": "2.3.2", + "bundled": true, + "dev": true, + "optional": true + }, + "tunnel-agent": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "tweetnacl": { + "version": "0.14.5", + "bundled": true, + "dev": true, + "optional": true + }, + "uid-number": { + "version": "0.0.6", + "bundled": true, + "dev": true, + "optional": true + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "uuid": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "verror": { + "version": "1.3.6", + "bundled": true, + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + } + } + }, + "fstream": { + "version": "https://registry.npmjs.org/fstream/-/fstream-0.1.31.tgz", + "integrity": "sha1-czfwWPu7vvqMn1YaKMqwhJICyYg=", + "dev": true, + "dependencies": { + "graceful-fs": { + "version": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.11.tgz", + "integrity": "sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg=", + "dev": true + }, + "mkdirp": { + "version": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true + } + } + }, + "function-loop": { + "version": "https://registry.npmjs.org/function-loop/-/function-loop-1.0.1.tgz", + "integrity": "sha1-gHa7MF6OajzO7ikgdl8zDRkPNAw=", + "dev": true + }, + "gaze": { + "version": "https://registry.npmjs.org/gaze/-/gaze-0.3.4.tgz", + "integrity": "sha1-X5S92gr+U7xxCWm81vKCVI1gwnk=", + "dev": true + }, + "generate-function": { + "version": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", + "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", + "dev": true + }, + "generate-object-property": { + "version": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", + "dev": true + }, + "getobject": { + "version": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz", + "integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=", + "dev": true + }, + "getpass": { + "version": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "dependencies": { + "assert-plus": { + "version": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "glob": { + "version": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz", + "integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=", + "dev": true, + "dependencies": { + "inherits": { + "version": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", + "integrity": "sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js=", + "dev": true + } + } + }, + "glob-base": { + "version": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "dev": true + }, + "glob-parent": { + "version": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true + }, + "globby": { + "version": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "dev": true, + "dependencies": { + "glob": { + "version": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", + "dev": true + }, + "minimatch": { + "version": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "dev": true + } + } + }, + "graceful-fs": { + "version": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", + "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=", + "dev": true + }, + "graceful-readlink": { + "version": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", + "dev": true + }, + "growl": { + "version": "https://registry.npmjs.org/growl/-/growl-1.7.0.tgz", + "integrity": "sha1-3i1mE20ALhErpw8/EMMc98NQsto=", + "dev": true + }, + "grunt": { + "version": "https://registry.npmjs.org/grunt/-/grunt-0.4.5.tgz", + "integrity": "sha1-VpN81RlDJK3/bSB2MYMqnWuk5/A=", + "dev": true + }, + "grunt-angular-templates": { + "version": "https://registry.npmjs.org/grunt-angular-templates/-/grunt-angular-templates-0.3.12.tgz", + "integrity": "sha1-Y55HkK9CEumy539qYqSrV6fnkS8=", + "dev": true + }, + "grunt-contrib": { + "version": "https://registry.npmjs.org/grunt-contrib/-/grunt-contrib-0.7.0.tgz", + "integrity": "sha1-7Wzwfltl6Y0aAK8Qnoryep5274M=", + "dev": true, + "dependencies": { + "async": { + "version": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", + "dev": true + }, + "grunt-contrib-clean": { + "version": "https://registry.npmjs.org/grunt-contrib-clean/-/grunt-contrib-clean-0.4.1.tgz", + "integrity": "sha1-f49G4vKnGH6cLQg6swJiqmpk4zQ=", + "dev": true + }, + "grunt-contrib-jshint": { + "version": "https://registry.npmjs.org/grunt-contrib-jshint/-/grunt-contrib-jshint-0.5.4.tgz", + "integrity": "sha1-baCGeLxjEFgM9sA3AprPvOo471k=", + "dev": true + }, + "grunt-contrib-less": { + "version": "https://registry.npmjs.org/grunt-contrib-less/-/grunt-contrib-less-0.5.2.tgz", + "integrity": "sha1-XoFCpB97nj8OCpd0P9WwkYm7oW8=", + "dev": true + }, + "grunt-contrib-uglify": { + "version": "https://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-0.2.7.tgz", + "integrity": "sha1-5r2lHgxAoUWfbOrUI8Ze/XJaG/c=", + "dev": true + }, + "grunt-lib-contrib": { + "version": "https://registry.npmjs.org/grunt-lib-contrib/-/grunt-lib-contrib-0.6.1.tgz", + "integrity": "sha1-P1att9oG6BR5XuJBWw6+X7iQPrs=", + "dev": true + }, + "source-map": { + "version": "https://registry.npmjs.org/source-map/-/source-map-0.1.34.tgz", + "integrity": "sha1-p8/omux7FoLDsZjQrPtH19CQVms=", + "dev": true + }, + "uglify-js": { + "version": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.4.24.tgz", + "integrity": "sha1-+tV1XB4Vd2WLsG/5q25UjJW+vW4=", + "dev": true + } + } + }, + "grunt-contrib-clean": { + "version": "https://registry.npmjs.org/grunt-contrib-clean/-/grunt-contrib-clean-0.5.0.tgz", + "integrity": "sha1-9T397ghJsce0Dp67umn0jExgecU=", + "dev": true + }, + "grunt-contrib-coffee": { + "version": "https://registry.npmjs.org/grunt-contrib-coffee/-/grunt-contrib-coffee-0.7.0.tgz", + "integrity": "sha1-ixIme3TnM4sfKcW4txj7n4mYLxM=", + "dev": true, + "dependencies": { + "coffee-script": { + "version": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.6.3.tgz", + "integrity": "sha1-Y1XTLPGwTN/2tITl5xF4Ky8MOb4=", + "dev": true + } + } + }, + "grunt-contrib-compass": { + "version": "https://registry.npmjs.org/grunt-contrib-compass/-/grunt-contrib-compass-0.2.0.tgz", + "integrity": "sha1-F2QloIQpOLaLkqwAceayJnWbChQ=", + "dev": true, + "dependencies": { + "tmp": { + "version": "https://registry.npmjs.org/tmp/-/tmp-0.0.16.tgz", + "integrity": "sha1-cE6gUTwVN1OJ71tt3oZXMFKPIkU=", + "dev": true + } + } + }, + "grunt-contrib-compress": { + "version": "https://registry.npmjs.org/grunt-contrib-compress/-/grunt-contrib-compress-0.5.3.tgz", + "integrity": "sha1-ujtbL/Q4xFMFeeaWLKuAaWWA6+0=", + "dev": true + }, + "grunt-contrib-concat": { + "version": "https://registry.npmjs.org/grunt-contrib-concat/-/grunt-contrib-concat-0.3.0.tgz", + "integrity": "sha1-SPoNQzbSm2U62CJaa9b4VrRIPjI=", + "dev": true + }, + "grunt-contrib-connect": { + "version": "https://registry.npmjs.org/grunt-contrib-connect/-/grunt-contrib-connect-0.3.0.tgz", + "integrity": "sha1-H6JTU/GtgLeSKIdYI1+v+YtYPKU=", + "dev": true + }, + "grunt-contrib-copy": { + "version": "https://registry.npmjs.org/grunt-contrib-copy/-/grunt-contrib-copy-0.4.1.tgz", + "integrity": "sha1-8HU7QK4hu3BtrvsLKZ4DzfX6nW4=", + "dev": true + }, + "grunt-contrib-csslint": { + "version": "https://registry.npmjs.org/grunt-contrib-csslint/-/grunt-contrib-csslint-0.1.2.tgz", + "integrity": "sha1-UFo/YW1MV5AUrkmgiHIU1dCZmrY=", + "dev": true + }, + "grunt-contrib-cssmin": { + "version": "https://registry.npmjs.org/grunt-contrib-cssmin/-/grunt-contrib-cssmin-0.6.2.tgz", + "integrity": "sha1-KATcDoH5jopU1h7uhKHT/ho6+OI=", + "dev": true, + "dependencies": { + "grunt-lib-contrib": { + "version": "https://registry.npmjs.org/grunt-lib-contrib/-/grunt-lib-contrib-0.6.1.tgz", + "integrity": "sha1-P1att9oG6BR5XuJBWw6+X7iQPrs=", + "dev": true + } + } + }, + "grunt-contrib-handlebars": { + "version": "https://registry.npmjs.org/grunt-contrib-handlebars/-/grunt-contrib-handlebars-0.5.12.tgz", + "integrity": "sha1-/a+Wm7yjLLIAg9WOqGAgn5KjWMc=", + "dev": true + }, + "grunt-contrib-htmlmin": { + "version": "https://registry.npmjs.org/grunt-contrib-htmlmin/-/grunt-contrib-htmlmin-0.1.3.tgz", + "integrity": "sha1-QQ3rfykFQCwQNLkufTzOSozAJG4=", + "dev": true, + "dependencies": { + "grunt-lib-contrib": { + "version": "https://registry.npmjs.org/grunt-lib-contrib/-/grunt-lib-contrib-0.6.1.tgz", + "integrity": "sha1-P1att9oG6BR5XuJBWw6+X7iQPrs=", + "dev": true + } + } + }, + "grunt-contrib-imagemin": { + "version": "https://registry.npmjs.org/grunt-contrib-imagemin/-/grunt-contrib-imagemin-0.1.4.tgz", + "integrity": "sha1-bYEHbg18GUKoMLUC39gIhJJF5pQ=", + "dev": true + }, + "grunt-contrib-jade": { + "version": "https://registry.npmjs.org/grunt-contrib-jade/-/grunt-contrib-jade-0.6.0.tgz", + "integrity": "sha1-ZqfmU/XTk15bU2Tk4E7mLs9JmpQ=", + "dev": true, + "dependencies": { + "commander": { + "version": "https://registry.npmjs.org/commander/-/commander-1.1.1.tgz", + "integrity": "sha1-UNFlGGiuYOzP8KLZ80WVN2vGsEE=", + "dev": true + }, + "jade": { + "version": "https://registry.npmjs.org/jade/-/jade-0.30.0.tgz", + "integrity": "sha1-nqgW2mG+pv70cJtNn2tELx4gW6M=", + "dev": true + } + } + }, + "grunt-contrib-jasmine": { + "version": "https://registry.npmjs.org/grunt-contrib-jasmine/-/grunt-contrib-jasmine-0.4.2.tgz", + "integrity": "sha1-PzYvSxzkB4qlbbnFpZhFzNOyUdc=", + "dev": true, + "dependencies": { + "graceful-fs": { + "version": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.1.14.tgz", + "integrity": "sha1-BweNtfY3f2Mh/Oqu30l94STclGU=", + "dev": true, + "optional": true + }, + "rimraf": { + "version": "https://registry.npmjs.org/rimraf/-/rimraf-2.0.3.tgz", + "integrity": "sha1-9QopZecUTpr9mYmC8V33BnMPVqk=", + "dev": true + } + } + }, + "grunt-contrib-jshint": { + "version": "https://registry.npmjs.org/grunt-contrib-jshint/-/grunt-contrib-jshint-0.10.0.tgz", + "integrity": "sha1-V+vMyofo8yevZkXYo8WG1IReTYE=", + "dev": true, + "dependencies": { + "cli": { + "version": "https://registry.npmjs.org/cli/-/cli-0.6.6.tgz", + "integrity": "sha1-Aq1Eo4Cr8nraxebwzdewQ9dMU+M=", + "dev": true + }, + "console-browserify": { + "version": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "dev": true + }, + "glob": { + "version": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", + "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", + "dev": true, + "dependencies": { + "minimatch": { + "version": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", + "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", + "dev": true + } + } + }, + "jshint": { + "version": "https://registry.npmjs.org/jshint/-/jshint-2.5.11.tgz", + "integrity": "sha1-4tlYWLuxqngwAQii6BCZ+wlWIuA=", + "dev": true + }, + "minimatch": { + "version": "https://registry.npmjs.org/minimatch/-/minimatch-1.0.0.tgz", + "integrity": "sha1-4N0hILSeG3JM6NcUxSCCKpQ4V20=", + "dev": true + }, + "shelljs": { + "version": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", + "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", + "dev": true + }, + "underscore": { + "version": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", + "dev": true + } + } + }, + "grunt-contrib-jst": { + "version": "https://registry.npmjs.org/grunt-contrib-jst/-/grunt-contrib-jst-0.5.1.tgz", + "integrity": "sha1-vWdqJ1j5dta2kjGZfZ5rnWCgr60=", + "dev": true, + "dependencies": { + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz", + "integrity": "sha1-j1dWDIO1n8JwvT1WG2kAQ0MOJVE=", + "dev": true + } + } + }, + "grunt-contrib-less": { + "version": "https://registry.npmjs.org/grunt-contrib-less/-/grunt-contrib-less-0.7.0.tgz", + "integrity": "sha1-NfZRPkfsXzyZGI1G76nc83gge+g=", + "dev": true, + "dependencies": { + "grunt-lib-contrib": { + "version": "https://registry.npmjs.org/grunt-lib-contrib/-/grunt-lib-contrib-0.6.1.tgz", + "integrity": "sha1-P1att9oG6BR5XuJBWw6+X7iQPrs=", + "dev": true + }, + "less": { + "version": "https://registry.npmjs.org/less/-/less-1.4.2.tgz", + "integrity": "sha1-t97v6Yo6h77jZEEbPfLR7+WkEtA=", + "dev": true + }, + "mkdirp": { + "version": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", + "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=", + "dev": true, + "optional": true + } + } + }, + "grunt-contrib-nodeunit": { + "version": "https://registry.npmjs.org/grunt-contrib-nodeunit/-/grunt-contrib-nodeunit-0.2.2.tgz", + "integrity": "sha1-06nHkIo4tqMbyiT2K6A+/DS7l2Y=", + "dev": true + }, + "grunt-contrib-qunit": { + "version": "https://registry.npmjs.org/grunt-contrib-qunit/-/grunt-contrib-qunit-0.2.2.tgz", + "integrity": "sha1-j7zqBfJLnXVrmD5AnVtMMr5/Hwg=", + "dev": true + }, + "grunt-contrib-requirejs": { + "version": "https://registry.npmjs.org/grunt-contrib-requirejs/-/grunt-contrib-requirejs-0.4.4.tgz", + "integrity": "sha1-h/IWWpgeSKRdIvjMUpnQk0AxuXI=", + "dev": true, + "dependencies": { + "requirejs": { + "version": "https://registry.npmjs.org/requirejs/-/requirejs-2.1.22.tgz", + "integrity": "sha1-3Xj9LTQYDA1ixyS1uK68BmTgNm8=", + "dev": true + } + } + }, + "grunt-contrib-sass": { + "version": "https://registry.npmjs.org/grunt-contrib-sass/-/grunt-contrib-sass-0.3.0.tgz", + "integrity": "sha1-S1/yFwoghQxIh0W3w/wR2RM7qRs=", + "dev": true + }, + "grunt-contrib-stylus": { + "version": "https://registry.npmjs.org/grunt-contrib-stylus/-/grunt-contrib-stylus-0.5.1.tgz", + "integrity": "sha1-bb4fYZ6zG12BEaxd/KqCpnfryRo=", + "dev": true + }, + "grunt-contrib-uglify": { + "version": "https://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-0.11.1.tgz", + "integrity": "sha1-XiKi9nbNEdhx/CoPCKqbKXMEUyU=", + "dev": true, + "dependencies": { + "async": { + "version": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", + "dev": true + }, + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + }, + "source-map": { + "version": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", + "dev": true + }, + "uglify-js": { + "version": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.6.4.tgz", + "integrity": "sha1-ZeovswWck5RpLxX+2HwrNsFrmt8=", + "dev": true + }, + "yargs": { + "version": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true + } + } + }, + "grunt-contrib-watch": { + "version": "https://registry.npmjs.org/grunt-contrib-watch/-/grunt-contrib-watch-0.4.4.tgz", + "integrity": "sha1-Mg/HfFzTO3PlRGzZ7ZGWEhFqpjw=", + "dev": true + }, + "grunt-contrib-yuidoc": { + "version": "https://registry.npmjs.org/grunt-contrib-yuidoc/-/grunt-contrib-yuidoc-0.4.0.tgz", + "integrity": "sha1-JuV2FqWmifS9YB4UifsiQGln0mM=", + "dev": true + }, + "grunt-git-describe": { + "version": "https://registry.npmjs.org/grunt-git-describe/-/grunt-git-describe-2.3.2.tgz", + "integrity": "sha1-KjJhOTCybZCtJEAVYIP1VaYVYWY=", + "dev": true + }, + "grunt-legacy-log": { + "version": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-0.1.3.tgz", + "integrity": "sha1-7ClCboAwIa9ZAp+H0vnNczWgVTE=", + "dev": true, + "dependencies": { + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", + "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", + "dev": true + }, + "underscore.string": { + "version": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz", + "integrity": "sha1-ccCL9rQosRM/N+ePo6Icgvcymw0=", + "dev": true + } + } + }, + "grunt-legacy-log-utils": { + "version": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-0.1.1.tgz", + "integrity": "sha1-wHBrndkGThFvNvI/5OawSGcsD34=", + "dev": true, + "dependencies": { + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", + "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", + "dev": true + }, + "underscore.string": { + "version": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz", + "integrity": "sha1-ccCL9rQosRM/N+ePo6Icgvcymw0=", + "dev": true + } + } + }, + "grunt-legacy-util": { + "version": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-0.2.0.tgz", + "integrity": "sha1-kzJIhNv343qf98Am3/RR2UqeVUs=", + "dev": true + }, + "grunt-lib-contrib": { + "version": "https://registry.npmjs.org/grunt-lib-contrib/-/grunt-lib-contrib-0.5.3.tgz", + "integrity": "sha1-6D+e5cigZZLW6CWCHZEhB4IIEzg=", + "dev": true + }, + "grunt-lib-phantomjs": { + "version": "https://registry.npmjs.org/grunt-lib-phantomjs/-/grunt-lib-phantomjs-0.3.1.tgz", + "integrity": "sha1-QhX+q7gbjTkwBbDnhFAfIK7nBTI=", + "dev": true + }, + "grunt-ng-annotate": { + "version": "https://registry.npmjs.org/grunt-ng-annotate/-/grunt-ng-annotate-0.3.0.tgz", + "integrity": "sha1-7GWyAXZ83f0I2WiDwuIb7vwkVJg=", + "dev": true + }, + "grunt-ngmin": { + "version": "https://registry.npmjs.org/grunt-ngmin/-/grunt-ngmin-0.0.3.tgz", + "integrity": "sha1-u8Ce9P51kdZ0zFMk96XkWdknEdc=", + "dev": true + }, + "grunt-s3": { + "version": "https://registry.npmjs.org/grunt-s3/-/grunt-s3-0.2.0-alpha.3.tgz", + "integrity": "sha1-4zKdLKpu2TxNvAOX4lfKporp7nw=", + "dev": true, + "dependencies": { + "temporary": { + "version": "https://registry.npmjs.org/temporary/-/temporary-0.0.5.tgz", + "integrity": "sha1-4pFrchdlF6bI+2fT+nilaOmyeGU=", + "dev": true + } + } + }, + "grunt-string-replace": { + "version": "https://registry.npmjs.org/grunt-string-replace/-/grunt-string-replace-0.2.8.tgz", + "integrity": "sha1-wD8WL0z+rymFCy0Zn9n6tg9gkNg=", + "dev": true, + "dependencies": { + "ansi-styles": { + "version": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", + "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=", + "dev": true + }, + "async": { + "version": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", + "dev": true + }, + "chalk": { + "version": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", + "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=", + "dev": true + }, + "strip-ansi": { + "version": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", + "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=", + "dev": true + } + } + }, + "grunt-util-args": { + "version": "https://registry.npmjs.org/grunt-util-args/-/grunt-util-args-0.0.3.tgz", + "integrity": "sha1-1PxMaDB2a2uOnfDNZnLhuxcuAFI=", + "dev": true + }, + "grunt-util-options": { + "version": "https://registry.npmjs.org/grunt-util-options/-/grunt-util-options-0.0.3.tgz", + "integrity": "sha1-fB0pJQtMMxY3a05mGWjGrM4/XoU=", + "dev": true + }, + "grunt-util-process": { + "version": "https://registry.npmjs.org/grunt-util-process/-/grunt-util-process-0.0.2.tgz", + "integrity": "sha1-qErZOnN3V+6q8Pgtimz0Uj7jcYY=", + "dev": true + }, + "grunt-util-property": { + "version": "https://registry.npmjs.org/grunt-util-property/-/grunt-util-property-0.0.1.tgz", + "integrity": "sha1-O+p5hyIl/J+iA0aOsqEknKrWcR4=", + "dev": true + }, + "grunt-util-spawn": { + "version": "https://registry.npmjs.org/grunt-util-spawn/-/grunt-util-spawn-0.0.2.tgz", + "integrity": "sha1-FfILcvaNOZYaQQ7MkmjovOczHuc=", + "dev": true + }, + "gzip-size": { + "version": "https://registry.npmjs.org/gzip-size/-/gzip-size-3.0.0.tgz", + "integrity": "sha1-VGGI6b3DN/Zzdy+BZgRks4nc5SA=", + "dev": true + }, + "handlebars": { + "version": "https://registry.npmjs.org/handlebars/-/handlebars-1.0.12.tgz", + "integrity": "sha1-GMbTRAw16RsZs/9YK5FRq0mF1Pw=", + "dev": true + }, + "har-schema": { + "version": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", + "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=", + "dev": true + }, + "har-validator": { + "version": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", + "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", + "dev": true, + "dependencies": { + "commander": { + "version": "https://registry.npmjs.org/commander/-/commander-2.10.0.tgz", + "integrity": "sha1-4fXTJF3iRtGlygRwL6GtG9fkBf4=", + "dev": true + } + } + }, + "has-ansi": { + "version": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true + }, + "has-color": { + "version": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", + "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=", + "dev": true + }, + "hasha": { + "version": "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz", + "integrity": "sha1-eNfL/B5tZjA/55g3NlmEUXsvbuE=", + "dev": true + }, + "hawk": { + "version": "https://registry.npmjs.org/hawk/-/hawk-0.10.2.tgz", + "integrity": "sha1-mzYd7pWpMWQObVBOBWCaj8OsRdI=", + "dev": true + }, + "hoek": { + "version": "https://registry.npmjs.org/hoek/-/hoek-0.7.6.tgz", + "integrity": "sha1-YPvZBFV1Qc0rh5Wr8wihs3cOFVo=", + "dev": true + }, + "hooker": { + "version": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz", + "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=", + "dev": true + }, + "html-minifier": { + "version": "https://registry.npmjs.org/html-minifier/-/html-minifier-0.5.6.tgz", + "integrity": "sha1-DxW0N8J7XOmqhKRMooUIgOkleZY=", + "dev": true + }, + "htmlparser2": { + "version": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", + "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", + "dev": true, + "dependencies": { + "readable-stream": { + "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true + } + } + }, + "http-errors": { + "version": "https://registry.npmjs.org/http-errors/-/http-errors-1.3.1.tgz", + "integrity": "sha1-GX4izevUGYWF6GlO9nhhl7ke2UI=", + "dev": true + }, + "http-proxy": { + "version": "https://registry.npmjs.org/http-proxy/-/http-proxy-0.10.4.tgz", + "integrity": "sha1-FLoM6qIZf4n6MN6p57CeGc2Twi8=", + "dev": true, + "dependencies": { + "optimist": { + "version": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true + }, + "pkginfo": { + "version": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.3.1.tgz", + "integrity": "sha1-Wyn2qB9wcXFC4J52W76rl7T4HiE=", + "dev": true + } + } + }, + "http-server": { + "version": "https://registry.npmjs.org/http-server/-/http-server-0.6.1.tgz", + "integrity": "sha1-BvzmXPK9QTKleL2sYv+suX1hOYE=", + "dev": true, + "dependencies": { + "opener": { + "version": "https://registry.npmjs.org/opener/-/opener-1.3.0.tgz", + "integrity": "sha1-EwumYiE/qELttM0DYdMaFTAaQ+I=", + "dev": true + }, + "optimist": { + "version": "https://registry.npmjs.org/optimist/-/optimist-0.5.2.tgz", + "integrity": "sha1-hcjBRUszFeSniUfoV7HfAzRQv7w=", + "dev": true + } + } + }, + "http-signature": { + "version": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "dev": true + }, + "https-proxy-agent": { + "version": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", + "integrity": "sha1-NffabEjOTdv6JkiRrFk+5f+GceY=", + "dev": true + }, + "i": { + "version": "https://registry.npmjs.org/i/-/i-0.3.5.tgz", + "integrity": "sha1-HSuFQVjsgWkRPGy39raAHpniEdU=", + "dev": true + }, + "iconv-lite": { + "version": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.2.11.tgz", + "integrity": "sha1-HOYKOleGSiktEyH/RgnKS7llrcg=", + "dev": true + }, + "inflight": { + "version": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true + }, + "inherits": { + "version": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "ini": { + "version": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", + "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=", + "dev": true + }, + "is-binary-path": { + "version": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true + }, + "is-buffer": { + "version": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz", + "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=", + "dev": true + }, + "is-dotfile": { + "version": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", + "dev": true + }, + "is-equal-shallow": { + "version": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "dev": true + }, + "is-extendable": { + "version": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-glob": { + "version": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true + }, + "is-my-json-valid": { + "version": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz", + "integrity": "sha1-8Hndm/2uZe4gOKrorLyGqxCeNpM=", + "dev": true + }, + "is-number": { + "version": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "dev": true + }, + "is-path-cwd": { + "version": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true + }, + "is-path-in-cwd": { + "version": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", + "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", + "dev": true + }, + "is-path-inside": { + "version": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz", + "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=", + "dev": true + }, + "is-posix-bracket": { + "version": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", + "dev": true + }, + "is-primitive": { + "version": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", + "dev": true + }, + "is-promise": { + "version": "https://registry.npmjs.org/is-promise/-/is-promise-1.0.1.tgz", + "integrity": "sha1-MVc3YcBX4zwukaq56W2gjO++duU=", + "dev": true + }, + "is-property": { + "version": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", + "dev": true + }, + "is-stream": { + "version": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-typedarray": { + "version": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "isarray": { + "version": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "isexe": { + "version": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "dependencies": { + "isarray": { + "version": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + } + } + }, + "isstream": { + "version": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "jade": { + "version": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", + "integrity": "sha1-jxDXl32NefL2/4YqgbBRPMslaGw=", + "dev": true, + "dependencies": { + "commander": { + "version": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", + "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", + "dev": true + }, + "mkdirp": { + "version": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", + "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=", + "dev": true + } + } + }, + "jasmine": { + "version": "https://registry.npmjs.org/jasmine/-/jasmine-2.6.0.tgz", + "integrity": "sha1-ayLnCIPo5YnUVjRhU7TSBt2+IX8=", + "dev": true, + "dependencies": { + "glob": { + "version": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", + "dev": true + }, + "minimatch": { + "version": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "dev": true + } + } + }, + "jasmine-core": { + "version": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.6.4.tgz", + "integrity": "sha1-3skmzQqfoof7bbXHVfpIfnTOysU=", + "dev": true + }, + "jasminewd2": { + "version": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.1.0.tgz", + "integrity": "sha1-2llSddGuYx3nNqwKfH2Fyfc+9lI=", + "dev": true + }, + "jpegtran-bin": { + "version": "https://registry.npmjs.org/jpegtran-bin/-/jpegtran-bin-0.1.7.tgz", + "integrity": "sha1-Iz2OEZAkPLqKZb2zSNBbiBItwVo=", + "dev": true + }, + "js-yaml": { + "version": "https://registry.npmjs.org/js-yaml/-/js-yaml-2.0.5.tgz", + "integrity": "sha1-olrmUJmZ6X3yeMZxnaEb0Gh3Q6g=", + "dev": true + }, + "jsbn": { + "version": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true, + "optional": true + }, + "jshint": { + "version": "https://registry.npmjs.org/jshint/-/jshint-2.0.1.tgz", + "integrity": "sha1-sEzek5Ryr9e6Ds+YzQF1up7URaQ=", + "dev": true, + "dependencies": { + "shelljs": { + "version": "https://registry.npmjs.org/shelljs/-/shelljs-0.1.4.tgz", + "integrity": "sha1-37vnjVbDwBaNL7eeEOzR28sH7A4=", + "dev": true + }, + "underscore": { + "version": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz", + "integrity": "sha1-YaajIBBiKvoHljvzJSA88SI51gQ=", + "dev": true + } + } + }, + "json-schema": { + "version": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-stable-stringify": { + "version": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true + }, + "json-stringify-safe": { + "version": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-3.0.0.tgz", + "integrity": "sha1-nbew5TDH8onF6MhDKvGRwv91pbM=", + "dev": true + }, + "jsonfile": { + "version": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "dev": true, + "dependencies": { + "graceful-fs": { + "version": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true, + "optional": true + } + } + }, + "jsonify": { + "version": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true + }, + "jsonpointer": { + "version": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", + "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", + "dev": true + }, + "jsprim": { + "version": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.0.tgz", + "integrity": "sha1-o7h+QCmNjDgFUtjMdiigu5WiKRg=", + "dev": true, + "dependencies": { + "assert-plus": { + "version": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "karma": { + "version": "https://registry.npmjs.org/karma/-/karma-0.12.37.tgz", + "integrity": "sha1-Gp9/3szWneLoNeBO26wuzT+mReQ=", + "dev": true, + "dependencies": { + "bytes": { + "version": "https://registry.npmjs.org/bytes/-/bytes-2.1.0.tgz", + "integrity": "sha1-rJPEEOL/ycx89LRks4KJBn9eR7Q=", + "dev": true + }, + "colors": { + "version": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", + "dev": true + }, + "connect": { + "version": "https://registry.npmjs.org/connect/-/connect-2.30.2.tgz", + "integrity": "sha1-jam8vooFTT0xjXTf7JA7XDmhtgk=", + "dev": true + }, + "cookie": { + "version": "https://registry.npmjs.org/cookie/-/cookie-0.1.3.tgz", + "integrity": "sha1-5zSlwUF/zkctWu+Cw4HKu2TRpDU=", + "dev": true + }, + "cookie-signature": { + "version": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true + }, + "debug": { + "version": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true + }, + "fresh": { + "version": "https://registry.npmjs.org/fresh/-/fresh-0.3.0.tgz", + "integrity": "sha1-ZR+DjiJCTnVm3hYdg1jKoZn4PU8=", + "dev": true + }, + "glob": { + "version": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "dev": true + }, + "graceful-fs": { + "version": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.11.tgz", + "integrity": "sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg=", + "dev": true + }, + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", + "dev": true + }, + "mime": { + "version": "https://registry.npmjs.org/mime/-/mime-1.3.6.tgz", + "integrity": "sha1-WR2E02U6awtKO5343lqoEI5y5eA=", + "dev": true + }, + "minimatch": { + "version": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", + "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", + "dev": true + }, + "ms": { + "version": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true + }, + "optimist": { + "version": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true + }, + "pause": { + "version": "https://registry.npmjs.org/pause/-/pause-0.1.0.tgz", + "integrity": "sha1-68ikqGGf8LioGsFRPDQ0/0af23Q=", + "dev": true + }, + "qs": { + "version": "https://registry.npmjs.org/qs/-/qs-4.0.0.tgz", + "integrity": "sha1-wx2bdOwn33XlQ6hseHKO2NRiNgc=", + "dev": true + }, + "rimraf": { + "version": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", + "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", + "dev": true, + "dependencies": { + "glob": { + "version": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", + "dev": true + }, + "minimatch": { + "version": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "dev": true + } + } + }, + "source-map": { + "version": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true + } + } + }, + "karma-chrome-launcher": { + "version": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-0.1.12.tgz", + "integrity": "sha1-CsDiLlc2UPZUExL9ynlcOCTM+WI=", + "dev": true + }, + "karma-firefox-launcher": { + "version": "https://registry.npmjs.org/karma-firefox-launcher/-/karma-firefox-launcher-0.1.7.tgz", + "integrity": "sha1-wF3YZTNpHmLzGVJZUJjovTV9OfM=", + "dev": true + }, + "karma-jasmine": { + "version": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-0.1.6.tgz", + "integrity": "sha1-MFRQV2mOvcvGMTLUe+Elt1svvFU=", + "dev": true + }, + "karma-junit-reporter": { + "version": "https://registry.npmjs.org/karma-junit-reporter/-/karma-junit-reporter-0.2.2.tgz", + "integrity": "sha1-TN1OIa/9PgkOe6c+PHZuqeE8Rbo=", + "dev": true + }, + "karma-requirejs": { + "version": "https://registry.npmjs.org/karma-requirejs/-/karma-requirejs-0.2.6.tgz", + "integrity": "sha1-GncMZPkBMgo4nGW0lEdGMmNy3vg=", + "dev": true + }, + "kew": { + "version": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz", + "integrity": "sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=", + "dev": true + }, + "keypress": { + "version": "https://registry.npmjs.org/keypress/-/keypress-0.1.0.tgz", + "integrity": "sha1-SjGI1CkbZrT2XtuZ+AaqmuKTWSo=", + "dev": true + }, + "kind-of": { + "version": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true + }, + "klaw": { + "version": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", + "dev": true, + "dependencies": { + "graceful-fs": { + "version": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true, + "optional": true + } + } + }, + "knox": { + "version": "https://registry.npmjs.org/knox/-/knox-0.8.10.tgz", + "integrity": "sha1-ai7c2sHSrjedHhmU1Vm5XCg7JYg=", + "dev": true, + "dependencies": { + "debug": { + "version": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", + "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=", + "dev": true + } + } + }, + "lazy-cache": { + "version": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "dev": true + }, + "lazystream": { + "version": "https://registry.npmjs.org/lazystream/-/lazystream-0.1.0.tgz", + "integrity": "sha1-GyXWPHcqTCDwpe0KnXf0hLbhaSA=", + "dev": true + }, + "lcov-parse": { + "version": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.10.tgz", + "integrity": "sha1-GwuP+ayceIklBYK3C3ExXZ2m2aM=", + "dev": true + }, + "less": { + "version": "https://registry.npmjs.org/less/-/less-1.3.3.tgz", + "integrity": "sha1-fujzAKQQgPNUTIDHpwzfamEoDPk=", + "dev": true + }, + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-0.9.2.tgz", + "integrity": "sha1-jzSZxSRdNG1oLlsNO0B2fgnxqSw=", + "dev": true + }, + "log-driver": { + "version": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.5.tgz", + "integrity": "sha1-euTsJXMC/XkNVXyxDJcQDYV7AFY=", + "dev": true + }, + "log4js": { + "version": "https://registry.npmjs.org/log4js/-/log4js-0.6.38.tgz", + "integrity": "sha1-LElBFmldb7JUgJQ9P8hy5mKlIv0=", + "dev": true, + "dependencies": { + "semver": { + "version": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", + "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=", + "dev": true + } + } + }, + "longest": { + "version": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "dev": true + }, + "lru-cache": { + "version": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", + "dev": true + }, + "marked": { + "version": "https://registry.npmjs.org/marked/-/marked-0.2.10.tgz", + "integrity": "sha1-1f1oJxyq5hxV0pHQe9UDTP9ec+4=", + "dev": true + }, + "maxmin": { + "version": "https://registry.npmjs.org/maxmin/-/maxmin-2.1.0.tgz", + "integrity": "sha1-TTsiCQPZXu5+t6x/qGTnLcCaMWY=", + "dev": true + }, + "media-typer": { + "version": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true + }, + "method-override": { + "version": "https://registry.npmjs.org/method-override/-/method-override-2.3.9.tgz", + "integrity": "sha1-vRUfLONM8Bp2ykAKuVwBKxAtj3E=", + "dev": true, + "dependencies": { + "methods": { + "version": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true + }, + "vary": { + "version": "https://registry.npmjs.org/vary/-/vary-1.1.1.tgz", + "integrity": "sha1-Z1Neu2lMHVIldFeYRmUyP1h+jTc=", + "dev": true + } + } + }, + "methods": { + "version": "https://registry.npmjs.org/methods/-/methods-0.0.1.tgz", + "integrity": "sha1-J3yQ+L7zlwlkWoNxxRw7bGSOBow=", + "dev": true + }, + "micromatch": { + "version": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true + }, + "mime": { + "version": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", + "integrity": "sha1-WCA+7Ybjpe8XrtK32evUfwpg3RA=", + "dev": true + }, + "mime-db": { + "version": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz", + "integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE=", + "dev": true + }, + "mime-types": { + "version": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz", + "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=", + "dev": true + }, + "minimatch": { + "version": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", + "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", + "dev": true + }, + "minimist": { + "version": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.3.tgz", + "integrity": "sha1-WV4lHBNww6aLqyE20ONIuBBa3xM=", + "dev": true + }, + "mocha": { + "version": "https://registry.npmjs.org/mocha/-/mocha-1.9.0.tgz", + "integrity": "sha1-FBBUsTywPOXOWa7OPWXVygG43wo=", + "dev": true, + "dependencies": { + "commander": { + "version": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", + "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", + "dev": true + }, + "ms": { + "version": "https://registry.npmjs.org/ms/-/ms-0.3.0.tgz", + "integrity": "sha1-A+3DSNYT5mpWSGz9rFO8vomcvWE=", + "dev": true + } + } + }, + "monocle": { + "version": "https://registry.npmjs.org/monocle/-/monocle-0.1.50.tgz", + "integrity": "sha1-mny9DMwQ3pX9eKBLm+skgq5JQLc=", + "dev": true + }, + "morgan": { + "version": "https://registry.npmjs.org/morgan/-/morgan-1.6.1.tgz", + "integrity": "sha1-X9gYOYxoGcuiinzWZk8pL+HAu/I=", + "dev": true, + "dependencies": { + "debug": { + "version": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true + }, + "ms": { + "version": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true + } + } + }, + "ms": { + "version": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "multiparty": { + "version": "https://registry.npmjs.org/multiparty/-/multiparty-3.3.2.tgz", + "integrity": "sha1-Nd5oBNwZZD5SSfPT473GyM4wHT8=", + "dev": true, + "dependencies": { + "readable-stream": { + "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true + }, + "stream-counter": { + "version": "https://registry.npmjs.org/stream-counter/-/stream-counter-0.2.0.tgz", + "integrity": "sha1-3tJmVWMZyLDiIoErnPOyb6fZR94=", + "dev": true + } + } + }, + "nan": { + "version": "https://registry.npmjs.org/nan/-/nan-1.0.0.tgz", + "integrity": "sha1-riT4hQgY1mL8q1rPfzuVv6oszzg=", + "dev": true + }, + "natives": { + "version": "https://registry.npmjs.org/natives/-/natives-1.1.0.tgz", + "integrity": "sha1-6f+EFBimsux6SV6TmYT3jxY+bjE=", + "dev": true + }, + "ncp": { + "version": "https://registry.npmjs.org/ncp/-/ncp-0.4.2.tgz", + "integrity": "sha1-q8xsvT7C7Spyn/bnwfqPAXhKhXQ=", + "dev": true + }, + "negotiator": { + "version": "https://registry.npmjs.org/negotiator/-/negotiator-0.5.3.tgz", + "integrity": "sha1-Jp1cR2gQ7JLtvntsLygxY4T5p+g=", + "dev": true + }, + "ng-annotate": { + "version": "https://registry.npmjs.org/ng-annotate/-/ng-annotate-0.9.11.tgz", + "integrity": "sha1-24MI1cqSRyq2DztTLfTLTwoTS2c=", + "dev": true, + "dependencies": { + "esprima": { + "version": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz", + "integrity": "sha1-CZNQL+r2aBODJXVvMPmlH+7sEek=", + "dev": true + }, + "optimist": { + "version": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true + } + } + }, + "ngmin": { + "version": "https://registry.npmjs.org/ngmin/-/ngmin-0.4.1.tgz", + "integrity": "sha1-v8HPSwd/FXT2wK1uE2cp2tar4Z8=", + "dev": true, + "dependencies": { + "commander": { + "version": "https://registry.npmjs.org/commander/-/commander-1.1.1.tgz", + "integrity": "sha1-UNFlGGiuYOzP8KLZ80WVN2vGsEE=", + "dev": true + } + } + }, + "nib": { + "version": "https://registry.npmjs.org/nib/-/nib-0.9.2.tgz", + "integrity": "sha1-8UVwzQyaN2CbO2YqXm/I+xxsJp4=", + "dev": true, + "dependencies": { + "stylus": { + "version": "https://registry.npmjs.org/stylus/-/stylus-0.31.0.tgz", + "integrity": "sha1-tPgHqgZ/Bxq3B/LIrhQ6syEeUbI=", + "dev": true + } + } + }, + "node-uuid": { + "version": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", + "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=", + "dev": true + }, + "nodeunit": { + "version": "https://registry.npmjs.org/nodeunit/-/nodeunit-0.8.8.tgz", + "integrity": "sha1-UelyJro6H5lueuDuanooN2Q66wI=", + "dev": true + }, + "nopt": { + "version": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "dev": true + }, + "noptify": { + "version": "https://registry.npmjs.org/noptify/-/noptify-0.0.3.tgz", + "integrity": "sha1-WPZUpz2XU98MUdlobckhBKZ/S7s=", + "dev": true, + "dependencies": { + "nopt": { + "version": "https://registry.npmjs.org/nopt/-/nopt-2.0.0.tgz", + "integrity": "sha1-ynQW8gpeP5w7hhgPlilfo9C1Lg0=", + "dev": true + } + } + }, + "normalize-path": { + "version": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true + }, + "number-is-nan": { + "version": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "nyc": { + "version": "https://registry.npmjs.org/nyc/-/nyc-11.0.3.tgz", + "integrity": "sha1-DCi8ZpqFFiFwm/eghQMDS+44ErY=", + "dev": true, + "dependencies": { + "align-text": { + "version": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "dev": true + }, + "amdefine": { + "version": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true + }, + "ansi-regex": { + "version": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "append-transform": { + "version": "https://registry.npmjs.org/append-transform/-/append-transform-0.4.0.tgz", + "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=", + "dev": true + }, + "archy": { + "version": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, + "arr-diff": { + "version": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true + }, + "arr-flatten": { + "version": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.0.3.tgz", + "integrity": "sha1-onTthawIhJtr14R8RYB0XcUa37E=", + "dev": true + }, + "array-unique": { + "version": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true + }, + "arrify": { + "version": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "async": { + "version": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "babel-code-frame": { + "version": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz", + "integrity": "sha1-AnYgvuVnqIwyVhV05/0IAdMxGOQ=", + "dev": true + }, + "babel-generator": { + "version": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.25.0.tgz", + "integrity": "sha1-M6GvcNXyiQrrRlpKd5PB32qeqfw=", + "dev": true + }, + "babel-messages": { + "version": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "dev": true + }, + "babel-runtime": { + "version": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz", + "integrity": "sha1-CpSJ8UTecO+zzkMArM2zKeL8VDs=", + "dev": true + }, + "babel-template": { + "version": "https://registry.npmjs.org/babel-template/-/babel-template-6.25.0.tgz", + "integrity": "sha1-ZlJBFmt8KqTGGdceGSlpVSsQwHE=", + "dev": true + }, + "babel-traverse": { + "version": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.25.0.tgz", + "integrity": "sha1-IldJfi/NGbie3BPEyROB+VEklvE=", + "dev": true + }, + "babel-types": { + "version": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz", + "integrity": "sha1-cK+ySNVmDl0Y+BHZHIMDtUE0oY4=", + "dev": true + }, + "babylon": { + "version": "https://registry.npmjs.org/babylon/-/babylon-6.17.4.tgz", + "integrity": "sha1-Pot0AriNIsNCPhN6FXeIOxX/hpo=", + "dev": true + }, + "balanced-match": { + "version": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "brace-expansion": { + "version": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "dev": true + }, + "braces": { + "version": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true + }, + "builtin-modules": { + "version": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "caching-transform": { + "version": "https://registry.npmjs.org/caching-transform/-/caching-transform-1.0.1.tgz", + "integrity": "sha1-bb2y8g+Nj7znnz6U6dF0Lc31wKE=", + "dev": true + }, + "camelcase": { + "version": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true, + "optional": true + }, + "center-align": { + "version": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "dev": true, + "optional": true + }, + "chalk": { + "version": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true + }, + "cliui": { + "version": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "optional": true, + "dependencies": { + "wordwrap": { + "version": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true, + "optional": true + } + } + }, + "code-point-at": { + "version": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "commondir": { + "version": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "concat-map": { + "version": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "convert-source-map": { + "version": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz", + "integrity": "sha1-ms1whRxtXf3ZPZKC5e35SgP/RrU=", + "dev": true + }, + "core-js": { + "version": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz", + "integrity": "sha1-TekR5mew6ukSTjQlS1OupvxhjT4=", + "dev": true + }, + "cross-spawn": { + "version": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", + "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", + "dev": true + }, + "debug": { + "version": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", + "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", + "dev": true + }, + "debug-log": { + "version": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.1.tgz", + "integrity": "sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8=", + "dev": true + }, + "decamelize": { + "version": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "default-require-extensions": { + "version": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-1.0.0.tgz", + "integrity": "sha1-836hXT4T/9m0N9M+GnW1+5eHTLg=", + "dev": true + }, + "detect-indent": { + "version": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "dev": true + }, + "error-ex": { + "version": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", + "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", + "dev": true + }, + "escape-string-regexp": { + "version": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esutils": { + "version": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "execa": { + "version": "https://registry.npmjs.org/execa/-/execa-0.5.1.tgz", + "integrity": "sha1-3j+4XLjW6RyFvLzrFkWBeFy1ezY=", + "dev": true + }, + "expand-brackets": { + "version": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true + }, + "expand-range": { + "version": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "dev": true + }, + "extglob": { + "version": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true + }, + "filename-regex": { + "version": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "dev": true + }, + "fill-range": { + "version": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", + "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", + "dev": true + }, + "find-cache-dir": { + "version": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-0.1.1.tgz", + "integrity": "sha1-yN765XyKUqinhPnjHFfHQumToLk=", + "dev": true + }, + "find-up": { + "version": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true + }, + "for-in": { + "version": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true + }, + "foreground-child": { + "version": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", + "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=", + "dev": true + }, + "fs.realpath": { + "version": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "get-caller-file": { + "version": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", + "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", + "dev": true + }, + "get-stream": { + "version": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", + "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=", + "dev": true + }, + "glob": { + "version": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", + "dev": true + }, + "glob-base": { + "version": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "dev": true + }, + "glob-parent": { + "version": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true + }, + "globals": { + "version": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha1-qjiWs+abSH8X4x7SFD1pqOMMLYo=", + "dev": true + }, + "graceful-fs": { + "version": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true + }, + "handlebars": { + "version": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.10.tgz", + "integrity": "sha1-PTDHGLCaPZbyPqTMH0A8TTup/08=", + "dev": true, + "dependencies": { + "source-map": { + "version": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true + } + } + }, + "has-ansi": { + "version": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true + }, + "has-flag": { + "version": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "hosted-git-info": { + "version": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.4.2.tgz", + "integrity": "sha1-AHa59GonBQbduq6lZJaJdGBhKmc=", + "dev": true + }, + "imurmurhash": { + "version": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true + }, + "inherits": { + "version": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "invariant": { + "version": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", + "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", + "dev": true + }, + "invert-kv": { + "version": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true + }, + "is-arrayish": { + "version": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-buffer": { + "version": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz", + "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=", + "dev": true + }, + "is-builtin-module": { + "version": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "dev": true + }, + "is-dotfile": { + "version": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", + "dev": true + }, + "is-equal-shallow": { + "version": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "dev": true + }, + "is-extendable": { + "version": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-finite": { + "version": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true + }, + "is-glob": { + "version": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true + }, + "is-number": { + "version": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "dev": true + }, + "is-posix-bracket": { + "version": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", + "dev": true + }, + "is-primitive": { + "version": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", + "dev": true + }, + "is-stream": { + "version": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-utf8": { + "version": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "isarray": { + "version": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.1.tgz", + "integrity": "sha1-c7+5mIhSmUFck9OKPprfeEp3qdo=", + "dev": true + }, + "istanbul-lib-hook": { + "version": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.0.7.tgz", + "integrity": "sha1-3WYH8DB2V4/n1vKmMM8UO0m6zdw=", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.7.3.tgz", + "integrity": "sha1-klsjkWPqvdaMxASPUsL6T4mez6c=", + "dev": true + }, + "istanbul-lib-report": { + "version": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz", + "integrity": "sha1-8OVfVmVf+jQiIIC3oM1HYOFAX8k=", + "dev": true, + "dependencies": { + "supports-color": { + "version": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true + } + } + }, + "istanbul-lib-source-maps": { + "version": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.1.tgz", + "integrity": "sha1-pv4ay6jOCO68Y45XLilNJnAIqgw=", + "dev": true + }, + "istanbul-reports": { + "version": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.1.1.tgz", + "integrity": "sha1-BCvlyJ4XW8P4ZSPKqynAFOd/7k4=", + "dev": true + }, + "js-tokens": { + "version": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.1.tgz", + "integrity": "sha1-COnxMkhKLEWjCQfp3E1VZ7fxFNc=", + "dev": true + }, + "jsesc": { + "version": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "dev": true + }, + "kind-of": { + "version": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true + }, + "lazy-cache": { + "version": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "dev": true, + "optional": true + }, + "lcid": { + "version": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true + }, + "load-json-file": { + "version": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true + }, + "locate-path": { + "version": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "path-exists": { + "version": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + }, + "longest": { + "version": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "dev": true + }, + "loose-envify": { + "version": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", + "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", + "dev": true + }, + "lru-cache": { + "version": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", + "integrity": "sha1-Yi4y6CSItJJ5EUpPns9F581rulU=", + "dev": true + }, + "md5-hex": { + "version": "https://registry.npmjs.org/md5-hex/-/md5-hex-1.3.0.tgz", + "integrity": "sha1-0sSv6YPENwZiF5uMrRRSGRNQRsQ=", + "dev": true + }, + "md5-o-matic": { + "version": "https://registry.npmjs.org/md5-o-matic/-/md5-o-matic-0.1.1.tgz", + "integrity": "sha1-givM1l4RfFFPqxdrJZRdVBAKA8M=", + "dev": true + }, + "mem": { + "version": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", + "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", + "dev": true + }, + "merge-source-map": { + "version": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.0.4.tgz", + "integrity": "sha1-pd5GU42uhNQRTMXqArR3KmNGcB8=", + "dev": true + }, + "micromatch": { + "version": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true + }, + "mimic-fn": { + "version": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz", + "integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=", + "dev": true + }, + "minimatch": { + "version": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "dev": true + }, + "minimist": { + "version": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true + }, + "ms": { + "version": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "normalize-package-data": { + "version": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.8.tgz", + "integrity": "sha1-2Bntoqne29H/pWPqQHHZNngilbs=", + "dev": true + }, + "normalize-path": { + "version": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true + }, + "npm-run-path": { + "version": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true + }, + "number-is-nan": { + "version": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "object-assign": { + "version": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object.omit": { + "version": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "dev": true + }, + "once": { + "version": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true + }, + "optimist": { + "version": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true + }, + "os-homedir": { + "version": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-locale": { + "version": "https://registry.npmjs.org/os-locale/-/os-locale-2.0.0.tgz", + "integrity": "sha1-FZGN7VEFIrge565aMJ1U9jn8OaQ=", + "dev": true + }, + "p-finally": { + "version": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-limit": { + "version": "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz", + "integrity": "sha1-sH/y2aXYi+yAYDWJWiurZqJ5iLw=", + "dev": true + }, + "p-locate": { + "version": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true + }, + "parse-glob": { + "version": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "dev": true + }, + "parse-json": { + "version": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true + }, + "path-exists": { + "version": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true + }, + "path-is-absolute": { + "version": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", + "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", + "dev": true + }, + "path-type": { + "version": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true + }, + "pify": { + "version": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true + }, + "pkg-dir": { + "version": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", + "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "dev": true, + "dependencies": { + "find-up": { + "version": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true + } + } + }, + "preserve": { + "version": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "dev": true + }, + "pseudomap": { + "version": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "randomatic": { + "version": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", + "integrity": "sha1-x6vpzIuHwLqodrGf3oP9RkeX44w=", + "dev": true, + "dependencies": { + "is-number": { + "version": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "dependencies": { + "kind-of": { + "version": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true + } + } + }, + "kind-of": { + "version": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true + } + } + }, + "read-pkg": { + "version": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true + }, + "read-pkg-up": { + "version": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "dependencies": { + "find-up": { + "version": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true + } + } + }, + "regenerator-runtime": { + "version": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", + "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=", + "dev": true + }, + "regex-cache": { + "version": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz", + "integrity": "sha1-mxpsNdTQ3871cRrmUejp09cRQUU=", + "dev": true + }, + "remove-trailing-separator": { + "version": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.0.2.tgz", + "integrity": "sha1-abBi2XhyetFNxrVrpKt3L9jXBRE=", + "dev": true + }, + "repeat-element": { + "version": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", + "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", + "dev": true + }, + "repeat-string": { + "version": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "repeating": { + "version": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true + }, + "require-directory": { + "version": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "resolve-from": { + "version": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", + "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=", + "dev": true + }, + "right-align": { + "version": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "dev": true, + "optional": true + }, + "rimraf": { + "version": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", + "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", + "dev": true + }, + "semver": { + "version": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "dev": true + }, + "set-blocking": { + "version": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "signal-exit": { + "version": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "slide": { + "version": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", + "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", + "dev": true + }, + "source-map": { + "version": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", + "dev": true + }, + "spawn-wrap": { + "version": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.3.7.tgz", + "integrity": "sha1-vri/RCbWSysGhx4Nfe4mQ/H40bw=", + "dev": true + }, + "spdx-correct": { + "version": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", + "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", + "dev": true + }, + "spdx-expression-parse": { + "version": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", + "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=", + "dev": true + }, + "spdx-license-ids": { + "version": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", + "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", + "dev": true + }, + "string-width": { + "version": "https://registry.npmjs.org/string-width/-/string-width-2.0.0.tgz", + "integrity": "sha1-Y1xUNsxypuDDh87KJ41OLuxSaH4=", + "dev": true, + "dependencies": { + "is-fullwidth-code-point": { + "version": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + } + } + }, + "strip-ansi": { + "version": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true + }, + "strip-bom": { + "version": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true + }, + "strip-eof": { + "version": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "supports-color": { + "version": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "test-exclude": { + "version": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.1.1.tgz", + "integrity": "sha1-TYSWSwlmsAh+zDNKLOAC09k0HiY=", + "dev": true + }, + "to-fast-properties": { + "version": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true + }, + "trim-right": { + "version": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, + "uglify-js": { + "version": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "dev": true, + "optional": true, + "dependencies": { + "yargs": { + "version": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "optional": true + } + } + }, + "uglify-to-browserify": { + "version": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "dev": true, + "optional": true + }, + "validate-npm-package-license": { + "version": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", + "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", + "dev": true + }, + "which": { + "version": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", + "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", + "dev": true + }, + "which-module": { + "version": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "window-size": { + "version": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "dev": true, + "optional": true + }, + "wordwrap": { + "version": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + }, + "wrap-ansi": { + "version": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "dependencies": { + "string-width": { + "version": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true + } + } + }, + "wrappy": { + "version": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write-file-atomic": { + "version": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz", + "integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=", + "dev": true + }, + "y18n": { + "version": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yallist": { + "version": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "yargs": { + "version": "https://registry.npmjs.org/yargs/-/yargs-8.0.2.tgz", + "integrity": "sha1-YpmpBVsc78lp/355wdkY3Osiw2A=", + "dev": true, + "dependencies": { + "camelcase": { + "version": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "cliui": { + "version": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "dependencies": { + "string-width": { + "version": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true + } + } + }, + "load-json-file": { + "version": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true + }, + "path-type": { + "version": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true + }, + "read-pkg": { + "version": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true + }, + "read-pkg-up": { + "version": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true + }, + "strip-bom": { + "version": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "yargs-parser": { + "version": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz", + "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", + "dev": true + } + } + }, + "yargs-parser": { + "version": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", + "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", + "dev": true, + "dependencies": { + "camelcase": { + "version": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true + } + } + } + } + }, + "oauth-sign": { + "version": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.2.0.tgz", + "integrity": "sha1-oOahcV2u0GLzIrYit/5a/RA1tuI=", + "dev": true + }, + "object-assign": { + "version": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object.omit": { + "version": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "dev": true + }, + "on-finished": { + "version": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true + }, + "on-headers": { + "version": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz", + "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=", + "dev": true + }, + "once": { + "version": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true + }, + "opener": { + "version": "https://registry.npmjs.org/opener/-/opener-1.4.3.tgz", + "integrity": "sha1-XG2ixdflgx6P+jlklQ+NZnSskLg=", + "dev": true + }, + "optimist": { + "version": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", + "integrity": "sha1-yQlBrVnkJzMokjB00s8ufLxuwNk=", + "dev": true + }, + "options": { + "version": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", + "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=", + "dev": true + }, + "optipng-bin": { + "version": "https://registry.npmjs.org/optipng-bin/-/optipng-bin-0.2.6.tgz", + "integrity": "sha1-9092muVblGGH7kbr4A5KKPZyBZA=", + "dev": true + }, + "ordered-ast-traverse": { + "version": "https://registry.npmjs.org/ordered-ast-traverse/-/ordered-ast-traverse-0.1.1.tgz", + "integrity": "sha1-/SWLcLsWmjgYeEOYv3q85CrjfVY=", + "dev": true + }, + "ordered-esprima-props": { + "version": "https://registry.npmjs.org/ordered-esprima-props/-/ordered-esprima-props-1.0.0.tgz", + "integrity": "sha1-DHzOKKuSuTUbOigYBtZ0vqNEOi4=", + "dev": true + }, + "os-homedir": { + "version": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-tmpdir": { + "version": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "own-or": { + "version": "https://registry.npmjs.org/own-or/-/own-or-1.0.0.tgz", + "integrity": "sha1-Tod/vtqaLsgAD7wLyuOWRe6L+Nw=", + "dev": true + }, + "own-or-env": { + "version": "https://registry.npmjs.org/own-or-env/-/own-or-env-1.0.0.tgz", + "integrity": "sha1-nvkg/IHi5jz1nUEQElg2jPT8pPs=", + "dev": true + }, + "package": { + "version": "https://registry.npmjs.org/package/-/package-1.0.1.tgz", + "integrity": "sha1-0lofmeJQbcsn1nBLg9yooxLk7cw=", + "dev": true + }, + "parse-glob": { + "version": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "dev": true + }, + "parseurl": { + "version": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz", + "integrity": "sha1-yKuMkiO6NIiKpkopeyiFO+wY2lY=", + "dev": true + }, + "path-is-absolute": { + "version": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-is-inside": { + "version": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "pause": { + "version": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=", + "dev": true + }, + "pegjs": { + "version": "https://registry.npmjs.org/pegjs/-/pegjs-0.7.0.tgz", + "integrity": "sha1-qqH4JPnnGX7ETiKlevUi9wDdaJ4=", + "dev": true + }, + "pend": { + "version": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true + }, + "performance-now": { + "version": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", + "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=", + "dev": true + }, + "phantomjs": { + "version": "https://registry.npmjs.org/phantomjs/-/phantomjs-1.9.20.tgz", + "integrity": "sha1-RCSsog4U0lXAsIia9va4lz2hDg0=", + "dev": true, + "dependencies": { + "async": { + "version": "https://registry.npmjs.org/async/-/async-2.5.0.tgz", + "integrity": "sha1-hDGQ/WtzV6C54clW7d3V7IRitU0=", + "dev": true + }, + "boom": { + "version": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "dev": true + }, + "combined-stream": { + "version": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "dev": true + }, + "cryptiles": { + "version": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "dev": true + }, + "delayed-stream": { + "version": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "forever-agent": { + "version": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "https://registry.npmjs.org/form-data/-/form-data-1.0.1.tgz", + "integrity": "sha1-rjFduaSQf6BlUCMEpm13M0de43w=", + "dev": true + }, + "hawk": { + "version": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "dev": true + }, + "hoek": { + "version": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", + "dev": true + }, + "json-stringify-safe": { + "version": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + }, + "oauth-sign": { + "version": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "dev": true + }, + "qs": { + "version": "https://registry.npmjs.org/qs/-/qs-5.2.1.tgz", + "integrity": "sha1-gB/uAw4LlFDWOFrcSKTMVbRK7fw=", + "dev": true + }, + "request": { + "version": "https://registry.npmjs.org/request/-/request-2.67.0.tgz", + "integrity": "sha1-ivdHgOK/EeoK6aqWXBHxGv0nJ0I=", + "dev": true + }, + "sntp": { + "version": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "dev": true + }, + "tunnel-agent": { + "version": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", + "dev": true + }, + "which": { + "version": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", + "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", + "dev": true + } + } + }, + "pify": { + "version": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true + }, + "pkginfo": { + "version": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.2.3.tgz", + "integrity": "sha1-cjnEKl72wwuPMoQ52bn/cQQkkPg=", + "dev": true + }, + "policyfile": { + "version": "https://registry.npmjs.org/policyfile/-/policyfile-0.0.4.tgz", + "integrity": "sha1-1rgurZiueeviKOLa9ZAzEeyYLk0=", + "dev": true + }, + "portfinder": { + "version": "https://registry.npmjs.org/portfinder/-/portfinder-0.2.1.tgz", + "integrity": "sha1-srmwFk+eF/o6nH2yME0KdRQMca0=", + "dev": true, + "dependencies": { + "mkdirp": { + "version": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.0.7.tgz", + "integrity": "sha1-2JtPDkw+XlylQjWTFnXglP4aUHI=", + "dev": true + } + } + }, + "preserve": { + "version": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "dev": true + }, + "pretty-bytes": { + "version": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-3.0.1.tgz", + "integrity": "sha1-J9AAjXeAY6C0gRuzXHnxvV1fvM8=", + "dev": true + }, + "prettysize": { + "version": "https://registry.npmjs.org/prettysize/-/prettysize-0.0.3.tgz", + "integrity": "sha1-FK//amReWRpN3xxykZwjtBRhgaE=", + "dev": true + }, + "process-nextick-args": { + "version": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true + }, + "progress": { + "version": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", + "dev": true + }, + "promise": { + "version": "https://registry.npmjs.org/promise/-/promise-2.0.0.tgz", + "integrity": "sha1-RmSKqdYFr10ucMMCS/WUNtoCuA4=", + "dev": true + }, + "protractor": { + "version": "https://registry.npmjs.org/protractor/-/protractor-5.1.0.tgz", + "integrity": "sha1-0mUPLx/mkDGq01KE7sHveaUGJaE=", + "dev": true, + "dependencies": { + "boom": { + "version": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "dev": true + }, + "caseless": { + "version": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "combined-stream": { + "version": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "dev": true + }, + "cryptiles": { + "version": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "dev": true + }, + "delayed-stream": { + "version": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "forever-agent": { + "version": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", + "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "dev": true + }, + "glob": { + "version": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", + "dev": true + }, + "har-validator": { + "version": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", + "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", + "dev": true + }, + "hawk": { + "version": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "dev": true + }, + "hoek": { + "version": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", + "dev": true + }, + "json-stringify-safe": { + "version": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + }, + "minimatch": { + "version": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "dev": true + }, + "oauth-sign": { + "version": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "dev": true + }, + "optimist": { + "version": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true + }, + "q": { + "version": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", + "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=", + "dev": true + }, + "qs": { + "version": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", + "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=", + "dev": true + }, + "request": { + "version": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", + "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", + "dev": true + }, + "rimraf": { + "version": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", + "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", + "dev": true + }, + "sax": { + "version": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha1-KBYjTiN4vdxOU1T6tcqold9xANk=", + "dev": true + }, + "semver": { + "version": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "dev": true + }, + "sntp": { + "version": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "dev": true + }, + "tough-cookie": { + "version": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", + "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", + "dev": true + }, + "tunnel-agent": { + "version": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true + }, + "uuid": { + "version": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", + "integrity": "sha1-PdPT55Crwk17DToDT/q6vijrvAQ=", + "dev": true + }, + "webdriver-manager": { + "version": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.0.6.tgz", + "integrity": "sha1-PfGkgZdwELTL+MnYXHpXeCjA5ws=", + "dev": true, + "dependencies": { + "minimist": { + "version": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "xml2js": { + "version": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.17.tgz", + "integrity": "sha1-F76T6q4/O3eTWceVtBlwWogX6Gg=", + "dev": true + }, + "xmlbuilder": { + "version": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-4.2.1.tgz", + "integrity": "sha1-qlijBBoGb5DqoWwvU4n/GfP0YaU=", + "dev": true + } + } + }, + "pseudomap": { + "version": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "punycode": { + "version": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "q": { + "version": "https://registry.npmjs.org/q/-/q-1.5.0.tgz", + "integrity": "sha1-3QG6ydBtMObyGa7LglPunr3DCPE=", + "dev": true + }, + "qs": { + "version": "https://registry.npmjs.org/qs/-/qs-0.6.5.tgz", + "integrity": "sha1-KUsmjksNQlD23eGbO4s0k13/FO8=", + "dev": true + }, + "qtek": { + "version": "https://registry.npmjs.org/qtek/-/qtek-0.3.9.tgz", + "integrity": "sha1-1Lsa+XNGYsMWa+uTL7Q6gJ9TagU=" + }, + "random-bytes": { + "version": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=", + "dev": true + }, + "randomatic": { + "version": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", + "integrity": "sha1-x6vpzIuHwLqodrGf3oP9RkeX44w=", + "dev": true, + "dependencies": { + "is-number": { + "version": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "dependencies": { + "kind-of": { + "version": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true + } + } + }, + "kind-of": { + "version": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true + } + } + }, + "range-parser": { + "version": "https://registry.npmjs.org/range-parser/-/range-parser-0.0.4.tgz", + "integrity": "sha1-wEJ//vUcEKy6B4KkbJYC50T/Ygs=", + "dev": true + }, + "raw-body": { + "version": "https://registry.npmjs.org/raw-body/-/raw-body-2.1.7.tgz", + "integrity": "sha1-rf6s4uT7MJgFgBTQjActzFl1h3Q=", + "dev": true, + "dependencies": { + "bytes": { + "version": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz", + "integrity": "sha1-fZcZb51br39pNeJZhVSe3SpsIzk=", + "dev": true + }, + "iconv-lite": { + "version": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", + "integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI=", + "dev": true + } + } + }, + "readable-stream": { + "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true + }, + "readdirp": { + "version": "https://registry.npmjs.org/readdirp/-/readdirp-0.2.5.tgz", + "integrity": "sha1-xMJ25Sl3riXbUZH+UdAIVQ8V2bs=", + "dev": true + }, + "redis": { + "version": "https://registry.npmjs.org/redis/-/redis-0.7.3.tgz", + "integrity": "sha1-7le3pE0l7BWU5ENl2BZfp9HUgRo=", + "dev": true, + "optional": true + }, + "regex-cache": { + "version": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz", + "integrity": "sha1-mxpsNdTQ3871cRrmUejp09cRQUU=", + "dev": true + }, + "remove-trailing-separator": { + "version": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.0.2.tgz", + "integrity": "sha1-abBi2XhyetFNxrVrpKt3L9jXBRE=", + "dev": true + }, + "repeat-element": { + "version": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", + "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", + "dev": true + }, + "repeat-string": { + "version": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "request": { + "version": "https://registry.npmjs.org/request/-/request-2.16.6.tgz", + "integrity": "sha1-hy/kRa5y3iZrN4edatfclI+gHK0=", + "dev": true, + "dependencies": { + "qs": { + "version": "https://registry.npmjs.org/qs/-/qs-0.5.6.tgz", + "integrity": "sha1-MbGtBYVnZRxSaSFQa5qHk5EaA4Q=", + "dev": true + } + } + }, + "request-progress": { + "version": "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz", + "integrity": "sha1-XTa7V5YcZzqlt4jbyBQf3yO0Tgg=", + "dev": true + }, + "requirejs": { + "version": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.3.tgz", + "integrity": "sha1-qln9OgKH6vQHlZoTgigES13WpqM=", + "dev": true + }, + "response-time": { + "version": "https://registry.npmjs.org/response-time/-/response-time-2.3.2.tgz", + "integrity": "sha1-/6cbq5UtYvfB1Jt0NDVfvGjf/Fo=", + "dev": true, + "dependencies": { + "depd": { + "version": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz", + "integrity": "sha1-4b2Cxqq2ztlluXuIsX7T5SjKGMM=", + "dev": true + } + } + }, + "right-align": { + "version": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "dev": true + }, + "rimraf": { + "version": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", + "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=", + "dev": true + }, + "rjs-build-analysis": { + "version": "https://registry.npmjs.org/rjs-build-analysis/-/rjs-build-analysis-0.0.3.tgz", + "integrity": "sha1-VVGKv5K/vikEVIVXGNM1f+0o8tI=", + "dev": true, + "dependencies": { + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-1.2.1.tgz", + "integrity": "sha1-7UexbkbwaytAMJto6RY8F+k+owQ=", + "dev": true + } + } + }, + "rndm": { + "version": "https://registry.npmjs.org/rndm/-/rndm-1.2.0.tgz", + "integrity": "sha1-8z/pz7Urv9UgqhgyO8ZdsRCht2w=", + "dev": true + }, + "safe-buffer": { + "version": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha1-iTMSr2myEj3vcfV4iQAWce6yyFM=", + "dev": true + }, + "saucelabs": { + "version": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.3.0.tgz", + "integrity": "sha1-0kDoAJ33+ocwbsRXimm6O1xCT+4=", + "dev": true + }, + "sax": { + "version": "https://registry.npmjs.org/sax/-/sax-0.5.8.tgz", + "integrity": "sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE=", + "dev": true + }, + "selenium-webdriver": { + "version": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.0.1.tgz", + "integrity": "sha1-ot6l2kqX9mcuiefKcnbO+jZRR6c=", + "dev": true, + "dependencies": { + "glob": { + "version": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", + "dev": true + }, + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + }, + "minimatch": { + "version": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "dev": true + }, + "rimraf": { + "version": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", + "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", + "dev": true + }, + "sax": { + "version": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha1-KBYjTiN4vdxOU1T6tcqold9xANk=", + "dev": true + }, + "tmp": { + "version": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", + "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=", + "dev": true + }, + "xml2js": { + "version": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.17.tgz", + "integrity": "sha1-F76T6q4/O3eTWceVtBlwWogX6Gg=", + "dev": true + }, + "xmlbuilder": { + "version": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-4.2.1.tgz", + "integrity": "sha1-qlijBBoGb5DqoWwvU4n/GfP0YaU=", + "dev": true + } + } + }, + "semver": { + "version": "https://registry.npmjs.org/semver/-/semver-1.0.14.tgz", + "integrity": "sha1-ysXi1Vpvv5WMsiCuhEBFBxx49nY=", + "dev": true + }, + "send": { + "version": "https://registry.npmjs.org/send/-/send-0.1.1.tgz", + "integrity": "sha1-C8/L0D3vbi2GEuGr+PSJW0UMYMg=", + "dev": true + }, + "serve-favicon": { + "version": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.3.2.tgz", + "integrity": "sha1-3UGeJo3gEqtysxnTN/IQUBP5OB8=", + "dev": true, + "dependencies": { + "fresh": { + "version": "https://registry.npmjs.org/fresh/-/fresh-0.3.0.tgz", + "integrity": "sha1-ZR+DjiJCTnVm3hYdg1jKoZn4PU8=", + "dev": true + }, + "ms": { + "version": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", + "dev": true + } + } + }, + "serve-index": { + "version": "https://registry.npmjs.org/serve-index/-/serve-index-1.7.3.tgz", + "integrity": "sha1-egV/xu4o3GP2RWbl+lexEahq7NI=", + "dev": true, + "dependencies": { + "debug": { + "version": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true + }, + "ms": { + "version": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true + } + } + }, + "serve-static": { + "version": "https://registry.npmjs.org/serve-static/-/serve-static-1.10.3.tgz", + "integrity": "sha1-zlpuzTEB/tXsCYJ9rCKpwpv7BTU=", + "dev": true, + "dependencies": { + "debug": { + "version": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true + }, + "depd": { + "version": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz", + "integrity": "sha1-4b2Cxqq2ztlluXuIsX7T5SjKGMM=", + "dev": true + }, + "fresh": { + "version": "https://registry.npmjs.org/fresh/-/fresh-0.3.0.tgz", + "integrity": "sha1-ZR+DjiJCTnVm3hYdg1jKoZn4PU8=", + "dev": true + }, + "mime": { + "version": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz", + "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=", + "dev": true + }, + "ms": { + "version": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true + }, + "range-parser": { + "version": "https://registry.npmjs.org/range-parser/-/range-parser-1.0.3.tgz", + "integrity": "sha1-aHKCNTXGkuLCoBA4Jq/YLC4P8XU=", + "dev": true + }, + "send": { + "version": "https://registry.npmjs.org/send/-/send-0.13.2.tgz", + "integrity": "sha1-dl52B8gFVFK7pvCwUllTUJhgNt4=", + "dev": true + }, + "statuses": { + "version": "https://registry.npmjs.org/statuses/-/statuses-1.2.1.tgz", + "integrity": "sha1-3e1FzBglbVHtQK7BQkidXGECbSg=", + "dev": true + } + } + }, + "set-immediate-shim": { + "version": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", + "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", + "dev": true + }, + "shelljs": { + "version": "https://registry.npmjs.org/shelljs/-/shelljs-0.2.6.tgz", + "integrity": "sha1-kEktcv/MgVmXa6umL7D2iE8MM3g=", + "dev": true + }, + "sigmund": { + "version": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", + "dev": true + }, + "signal-exit": { + "version": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "simple-fmt": { + "version": "https://registry.npmjs.org/simple-fmt/-/simple-fmt-0.1.0.tgz", + "integrity": "sha1-GRv1ZqWeZTBILLJatTtKjchcOms=", + "dev": true + }, + "simple-is": { + "version": "https://registry.npmjs.org/simple-is/-/simple-is-0.2.0.tgz", + "integrity": "sha1-Krt1qt453rXMgVzhDmGRFkhQuvA=", + "dev": true + }, + "sntp": { + "version": "https://registry.npmjs.org/sntp/-/sntp-0.1.4.tgz", + "integrity": "sha1-XvSBuVGnspr/30r9fyaDj8ESD4Q=", + "dev": true + }, + "socket.io": { + "version": "https://registry.npmjs.org/socket.io/-/socket.io-0.9.16.tgz", + "integrity": "sha1-O6sEROSbVfu8FXQk29Qao3WlGnY=", + "dev": true + }, + "socket.io-client": { + "version": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-0.9.16.tgz", + "integrity": "sha1-TadRXF53MEHRtCOXBBW8xDDzX8Y=", + "dev": true, + "dependencies": { + "uglify-js": { + "version": "https://registry.npmjs.org/uglify-js/-/uglify-js-1.2.5.tgz", + "integrity": "sha1-tULCx29477NLIAsgF3Y0Mw/3ArY=", + "dev": true + } + } + }, + "source-map": { + "version": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", + "dev": true + }, + "source-map-support": { + "version": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.15.tgz", + "integrity": "sha1-AyAt9lwG0r2MfsI2KhkwVv7407E=", + "dev": true, + "dependencies": { + "source-map": { + "version": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", + "dev": true + } + } + }, + "sprintf-js": { + "version": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "sshpk": { + "version": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", + "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "dev": true, + "dependencies": { + "assert-plus": { + "version": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "stable": { + "version": "https://registry.npmjs.org/stable/-/stable-0.1.6.tgz", + "integrity": "sha1-kQ9dKu17Ugxud3SZwfMuE5/eyxA=", + "dev": true + }, + "stack-utils": { + "version": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.1.tgz", + "integrity": "sha1-1PM6tU6OOHeLDKXP07OvsS22hiA=", + "dev": true + }, + "statuses": { + "version": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=", + "dev": true + }, + "stream-counter": { + "version": "https://registry.npmjs.org/stream-counter/-/stream-counter-0.1.0.tgz", + "integrity": "sha1-oDXkKTYftX82Fgbhf82Ki5Z3Mns=", + "dev": true + }, + "string_decoder": { + "version": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "stringmap": { + "version": "https://registry.npmjs.org/stringmap/-/stringmap-0.2.2.tgz", + "integrity": "sha1-VWwTeyWPlCuHdvWy71gqoGnX0bE=", + "dev": true + }, + "stringset": { + "version": "https://registry.npmjs.org/stringset/-/stringset-0.2.1.tgz", + "integrity": "sha1-7yWcTjSTRDd/zRyRPdLoSMnAQrU=", + "dev": true + }, + "stringstream": { + "version": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", + "dev": true + }, + "strip-ansi": { + "version": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true + }, + "strip-json-comments": { + "version": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", + "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", + "dev": true + }, + "stylus": { + "version": "https://registry.npmjs.org/stylus/-/stylus-0.32.1.tgz", + "integrity": "sha1-PSgnW9nxgQhfjdD6UqhVlpaXghI=", + "dev": true + }, + "supports-color": { + "version": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "tap": { + "version": "https://registry.npmjs.org/tap/-/tap-10.7.0.tgz", + "integrity": "sha1-7N4evSuGmB90GuCJ8USMnylKxUg=", + "dev": true, + "dependencies": { + "argparse": { + "version": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", + "dev": true + }, + "esprima": { + "version": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true + }, + "glob": { + "version": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", + "dev": true + }, + "isarray": { + "version": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "js-yaml": { + "version": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.8.4.tgz", + "integrity": "sha1-UgtFZPhlc7qWZir4Woyvp7S1pvY=", + "dev": true + }, + "minimatch": { + "version": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "dev": true + }, + "readable-stream": { + "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.2.tgz", + "integrity": "sha1-WgTfBeT1f+Pw3Gj90R3FyXx+b00=", + "dev": true + }, + "string_decoder": { + "version": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", + "dev": true + } + } + }, + "tap-mocha-reporter": { + "version": "https://registry.npmjs.org/tap-mocha-reporter/-/tap-mocha-reporter-3.0.6.tgz", + "integrity": "sha1-Eqvpf/QJpabsw9cLbbo02CGEp3A=", + "dev": true, + "dependencies": { + "argparse": { + "version": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", + "dev": true + }, + "diff": { + "version": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", + "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", + "dev": true + }, + "esprima": { + "version": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true + }, + "glob": { + "version": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", + "dev": true + }, + "isarray": { + "version": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true, + "optional": true + }, + "js-yaml": { + "version": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.8.4.tgz", + "integrity": "sha1-UgtFZPhlc7qWZir4Woyvp7S1pvY=", + "dev": true + }, + "minimatch": { + "version": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "dev": true + }, + "readable-stream": { + "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.2.tgz", + "integrity": "sha1-WgTfBeT1f+Pw3Gj90R3FyXx+b00=", + "dev": true, + "optional": true + }, + "string_decoder": { + "version": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", + "dev": true, + "optional": true + } + } + }, + "tap-parser": { + "version": "https://registry.npmjs.org/tap-parser/-/tap-parser-5.4.0.tgz", + "integrity": "sha1-aQfolyXXt/pq5B7ixGTD20MYiuw=", + "dev": true, + "dependencies": { + "argparse": { + "version": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", + "dev": true + }, + "esprima": { + "version": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true + }, + "isarray": { + "version": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true, + "optional": true + }, + "js-yaml": { + "version": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.8.4.tgz", + "integrity": "sha1-UgtFZPhlc7qWZir4Woyvp7S1pvY=", + "dev": true + }, + "readable-stream": { + "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.2.tgz", + "integrity": "sha1-WgTfBeT1f+Pw3Gj90R3FyXx+b00=", + "dev": true, + "optional": true + }, + "string_decoder": { + "version": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", + "dev": true, + "optional": true + } + } + }, + "tar": { + "version": "https://registry.npmjs.org/tar/-/tar-0.1.20.tgz", + "integrity": "sha1-QpQLrltfIsdEg2mRJvnz8nRJyxM=", + "dev": true + }, + "temporary": { + "version": "https://registry.npmjs.org/temporary/-/temporary-0.0.8.tgz", + "integrity": "sha1-oYqYHSi6jKNgJ/s8MFOMPst0CsA=", + "dev": true + }, + "throttleit": { + "version": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", + "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=", + "dev": true + }, + "tiny-lr": { + "version": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-0.0.4.tgz", + "integrity": "sha1-gGGFR/Y/aX0Fy0DEwsSwg1Ia77Y=", + "dev": true, + "dependencies": { + "debug": { + "version": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", + "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=", + "dev": true + }, + "qs": { + "version": "https://registry.npmjs.org/qs/-/qs-0.5.6.tgz", + "integrity": "sha1-MbGtBYVnZRxSaSFQa5qHk5EaA4Q=", + "dev": true + } + } + }, + "tinycolor": { + "version": "https://registry.npmjs.org/tinycolor/-/tinycolor-0.0.1.tgz", + "integrity": "sha1-MgtaUtg6u1l42Bo+iH1K77FaYWQ=", + "dev": true + }, + "tmatch": { + "version": "https://registry.npmjs.org/tmatch/-/tmatch-3.1.0.tgz", + "integrity": "sha1-cBJk/XWC0BRKgMha8zWMyiacceM=", + "dev": true + }, + "tmp": { + "version": "https://registry.npmjs.org/tmp/-/tmp-0.0.23.tgz", + "integrity": "sha1-3odKpel0qF8KMs39vXRmPLO9nHQ=", + "dev": true + }, + "tough-cookie": { + "version": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.2.tgz", + "integrity": "sha1-yDoYMPTl7wuT7yo0iOck+N4Basc=", + "dev": true + }, + "transformers": { + "version": "https://registry.npmjs.org/transformers/-/transformers-2.0.1.tgz", + "integrity": "sha1-NSEx3865OnUy3HU1pPFCUQQ1o5Q=", + "dev": true, + "dependencies": { + "uglify-js": { + "version": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.2.5.tgz", + "integrity": "sha1-puAqcNg5eSuXgEiLe4sYTAlcmcc=", + "dev": true + } + } + }, + "trivial-deferred": { + "version": "https://registry.npmjs.org/trivial-deferred/-/trivial-deferred-1.0.1.tgz", + "integrity": "sha1-N21NKdlR1jaKb3oK6FwvTV4GWPM=", + "dev": true + }, + "tryor": { + "version": "https://registry.npmjs.org/tryor/-/tryor-0.1.2.tgz", + "integrity": "sha1-gUXkynyv9ArN48z5Rui4u3W0Fys=", + "dev": true + }, + "tsame": { + "version": "https://registry.npmjs.org/tsame/-/tsame-1.1.2.tgz", + "integrity": "sha1-XOAAKs9oWUJ4nGMBh5eiql5rA8U=", + "dev": true + }, + "tsscmp": { + "version": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.5.tgz", + "integrity": "sha1-fcSjOvcVgatDN9qR2FylQn69mpc=", + "dev": true + }, + "tunnel-agent": { + "version": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.2.0.tgz", + "integrity": "sha1-aFPCr7GyEJ5FYp5JK9419Fnqaeg=", + "dev": true + }, + "tweetnacl": { + "version": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true, + "optional": true + }, + "type-is": { + "version": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", + "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=", + "dev": true + }, + "typedarray": { + "version": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "uglify-js": { + "version": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.3.6.tgz", + "integrity": "sha1-+gmEdwtCi3qbKoBY9GNV0U/vIRo=", + "dev": true, + "dependencies": { + "async": { + "version": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", + "dev": true + } + } + }, + "uglify-to-browserify": { + "version": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "dev": true + }, + "uid-safe": { + "version": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.4.tgz", + "integrity": "sha1-Otbzg2jG1MjHXsF2I/t5qh0HHYE=", + "dev": true + }, + "ultron": { + "version": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", + "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=", + "dev": true + }, + "underscore": { + "version": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", + "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=", + "dev": true + }, + "underscore.deferred": { + "version": "https://registry.npmjs.org/underscore.deferred/-/underscore.deferred-0.1.5.tgz", + "integrity": "sha1-R+rWDJiL8M8yIL+IQ/Ni4Ogk5ok=", + "dev": true + }, + "underscore.string": { + "version": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.2.1.tgz", + "integrity": "sha1-18D6KvXVoaZ/QlPa7pgTLnM/Dxk=", + "dev": true + }, + "unicode-length": { + "version": "https://registry.npmjs.org/unicode-length/-/unicode-length-1.0.3.tgz", + "integrity": "sha1-Wtp6f+1RhBpBijKM8UlHisg1irs=", + "dev": true + }, + "union": { + "version": "https://registry.npmjs.org/union/-/union-0.3.8.tgz", + "integrity": "sha1-JqcCpNNSi0NYyXEcir/2zJHSQlc=", + "dev": true, + "dependencies": { + "qs": { + "version": "https://registry.npmjs.org/qs/-/qs-0.5.6.tgz", + "integrity": "sha1-MbGtBYVnZRxSaSFQa5qHk5EaA4Q=", + "dev": true + } + } + }, + "unpipe": { + "version": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "uri-path": { + "version": "https://registry.npmjs.org/uri-path/-/uri-path-1.0.0.tgz", + "integrity": "sha1-l0fwGDWJM8Md4PzP2C0TjmcmLjI=", + "dev": true + }, + "useragent": { + "version": "https://registry.npmjs.org/useragent/-/useragent-2.1.13.tgz", + "integrity": "sha1-u6Q+iqJNXOuDwpN0c+EC4h33TBA=", + "dev": true, + "dependencies": { + "lru-cache": { + "version": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.2.4.tgz", + "integrity": "sha1-bGWGGb7PFAMdDQtZSxYELOTcBj0=", + "dev": true + } + } + }, + "util-deprecate": { + "version": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "utile": { + "version": "https://registry.npmjs.org/utile/-/utile-0.2.1.tgz", + "integrity": "sha1-kwyI6ZCY1iIINMNWy9mncFItkNc=", + "dev": true, + "dependencies": { + "async": { + "version": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", + "dev": true + } + } + }, + "utils-merge": { + "version": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz", + "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg=", + "dev": true + }, + "vary": { + "version": "https://registry.npmjs.org/vary/-/vary-1.0.1.tgz", + "integrity": "sha1-meSYFWaihhGN+yuBc1ffeZM3bRA=", + "dev": true + }, + "verror": { + "version": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", + "integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=", + "dev": true + }, + "vhost": { + "version": "https://registry.npmjs.org/vhost/-/vhost-3.0.2.tgz", + "integrity": "sha1-L7HezUxGaqiLD5NBrzPcGv8keNU=", + "dev": true + }, + "webdriver-js-extender": { + "version": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-1.0.0.tgz", + "integrity": "sha1-gcUzqeM9W/tZe05j4s2yW1R3dRU=", + "dev": true, + "dependencies": { + "adm-zip": { + "version": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.4.tgz", + "integrity": "sha1-ph7VrmkFw66lizplfSUDMJEFJzY=", + "dev": true + }, + "sax": { + "version": "https://registry.npmjs.org/sax/-/sax-0.6.1.tgz", + "integrity": "sha1-VjsZx8HeiS4Jv8Ty/DDjwn8JUrk=", + "dev": true + }, + "selenium-webdriver": { + "version": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-2.53.3.tgz", + "integrity": "sha1-0p/1qVff8aG0ncRXdW5OS/vc4IU=", + "dev": true + }, + "tmp": { + "version": "https://registry.npmjs.org/tmp/-/tmp-0.0.24.tgz", + "integrity": "sha1-1qXhmNFKmDXMby18PZ4wJCjIzxI=", + "dev": true + }, + "ws": { + "version": "https://registry.npmjs.org/ws/-/ws-1.1.4.tgz", + "integrity": "sha1-V/QNA2gy5fUFVmKjl8Tedu1mv2E=", + "dev": true + }, + "xml2js": { + "version": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.4.tgz", + "integrity": "sha1-MREBAAMAiuGSQOuhdJe1fHKcVV0=", + "dev": true + }, + "xmlbuilder": { + "version": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.1.tgz", + "integrity": "sha1-kc1wiXdVNj66V8Et3uq0o0GmH2U=", + "dev": true + } + } + }, + "which": { + "version": "https://registry.npmjs.org/which/-/which-1.0.9.tgz", + "integrity": "sha1-RgwdoPgQED0DIam2M6+eV15kSG8=", + "dev": true + }, + "window-size": { + "version": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "dev": true + }, + "wordwrap": { + "version": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + }, + "wrappy": { + "version": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "ws": { + "version": "https://registry.npmjs.org/ws/-/ws-0.4.32.tgz", + "integrity": "sha1-eHphVEFPPJntg8V3IVOyD+sM7DI=", + "dev": true, + "dependencies": { + "commander": { + "version": "https://registry.npmjs.org/commander/-/commander-2.1.0.tgz", + "integrity": "sha1-0SG7roYNmZKj1Re6lvVliOR8Z4E=", + "dev": true + } + } + }, + "xml2js": { + "version": "https://registry.npmjs.org/xml2js/-/xml2js-0.2.8.tgz", + "integrity": "sha1-m4FpCTFjH/CdGVdUn69U9PmAs8I=", + "dev": true + }, + "xmlbuilder": { + "version": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-0.4.2.tgz", + "integrity": "sha1-F3bWXz/brUcKCNhgTN6xxOVA/4M=", + "dev": true + }, + "xmlhttprequest": { + "version": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.4.2.tgz", + "integrity": "sha1-AUU6HZvtHo8XL2SVu/TIxCYyFQA=", + "dev": true + }, + "xtend": { + "version": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true + }, + "yallist": { + "version": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "yapool": { + "version": "https://registry.npmjs.org/yapool/-/yapool-1.0.0.tgz", + "integrity": "sha1-9pPymjFbUNmp2iZGp6ZkXJaYW2o=", + "dev": true + }, + "yargs": { + "version": "https://registry.npmjs.org/yargs/-/yargs-3.5.4.tgz", + "integrity": "sha1-2K/49mXpTDS9JZvevRv68N3TU2E=", + "dev": true, + "dependencies": { + "wordwrap": { + "version": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true + } + } + }, + "yauzl": { + "version": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", + "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=", + "dev": true + }, + "ycssmin": { + "version": "https://registry.npmjs.org/ycssmin/-/ycssmin-1.0.1.tgz", + "integrity": "sha1-fN3o23jPqwDSkBw7IwHjBPr03xY=", + "dev": true, + "optional": true + }, + "yui": { + "version": "https://registry.npmjs.org/yui/-/yui-3.14.1.tgz", + "integrity": "sha1-h+wcINkcEvV5/2T2OO65GQASkYM=", + "dev": true, + "dependencies": { + "asn1": { + "version": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz", + "integrity": "sha1-VZvhg3bQik7E2+gId9J4GGObLfc=", + "dev": true + }, + "assert-plus": { + "version": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.2.tgz", + "integrity": "sha1-2T/9u2esVQd3m+MWp9ZRRkF77vg=", + "dev": true + }, + "async": { + "version": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", + "dev": true + }, + "aws-sign": { + "version": "https://registry.npmjs.org/aws-sign/-/aws-sign-0.3.0.tgz", + "integrity": "sha1-PYHKabR0seFlGHKLUcJP8Lvtxuk=", + "dev": true + }, + "boom": { + "version": "https://registry.npmjs.org/boom/-/boom-0.4.2.tgz", + "integrity": "sha1-emNune1O/O+xnO9JR6PGffrukRs=", + "dev": true, + "dependencies": { + "hoek": { + "version": "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz", + "integrity": "sha1-PTIkYrrfB3Fup+uFuviAec3c5QU=", + "dev": true + } + } + }, + "cookie-jar": { + "version": "https://registry.npmjs.org/cookie-jar/-/cookie-jar-0.3.0.tgz", + "integrity": "sha1-vJon1OK5fhhs1XyeIGPLmfpozMw=", + "dev": true + }, + "cryptiles": { + "version": "https://registry.npmjs.org/cryptiles/-/cryptiles-0.2.2.tgz", + "integrity": "sha1-7ZH/HxetE9N0gohZT4pIoNJvMlw=", + "dev": true + }, + "forever-agent": { + "version": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz", + "integrity": "sha1-bQ4JxJIflKJ/Y9O0nF/v8epMUTA=", + "dev": true + }, + "form-data": { + "version": "https://registry.npmjs.org/form-data/-/form-data-0.0.8.tgz", + "integrity": "sha1-CJDNEAXFzOzAudJKiAUskkQtDbU=", + "dev": true + }, + "hawk": { + "version": "https://registry.npmjs.org/hawk/-/hawk-0.13.1.tgz", + "integrity": "sha1-NheViCH1gxHk1/beKR/KZitBLvQ=", + "dev": true + }, + "hoek": { + "version": "https://registry.npmjs.org/hoek/-/hoek-0.8.5.tgz", + "integrity": "sha1-Hp/XcO9+vgJ0rfy1sIBqAlpeTp8=", + "dev": true + }, + "http-signature": { + "version": "https://registry.npmjs.org/http-signature/-/http-signature-0.9.11.tgz", + "integrity": "sha1-nognFFcjFeZ5Cl0KeVXv/x8Z5lM=", + "dev": true + }, + "json-stringify-safe": { + "version": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-4.0.0.tgz", + "integrity": "sha1-d8JxqupUMC5o7+rMtWq78GqbGlQ=", + "dev": true + }, + "oauth-sign": { + "version": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz", + "integrity": "sha1-y1QPk7srIqfVlBaRoojWDo6pOG4=", + "dev": true + }, + "request": { + "version": "https://registry.npmjs.org/request/-/request-2.21.0.tgz", + "integrity": "sha1-VyirnEXlqHyZ2szVMCmLZnOoaNc=", + "dev": true + }, + "sntp": { + "version": "https://registry.npmjs.org/sntp/-/sntp-0.2.4.tgz", + "integrity": "sha1-+4hfGLDzqtGJ+CSGJTa87ux1CQA=", + "dev": true, + "dependencies": { + "hoek": { + "version": "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz", + "integrity": "sha1-PTIkYrrfB3Fup+uFuviAec3c5QU=", + "dev": true + } + } + }, + "tunnel-agent": { + "version": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.3.0.tgz", + "integrity": "sha1-rWgbaPUyGtKCfEz7G31d8s/pQu4=", + "dev": true + } + } + }, + "yuidocjs": { + "version": "https://registry.npmjs.org/yuidocjs/-/yuidocjs-0.3.50.tgz", + "integrity": "sha1-kGCl92Wog7EAtWPsatEFxdUzacE=", + "dev": true, + "dependencies": { + "graceful-fs": { + "version": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz", + "integrity": "sha1-fNLNsiiko/Nule+mzBQt59GhNtA=", + "dev": true + } + } + }, + "zeparser": { + "version": "https://registry.npmjs.org/zeparser/-/zeparser-0.0.5.tgz", + "integrity": "sha1-A3JlYbwmjy5URPVMZlt/1KjAKeI=", + "dev": true + }, + "zlib-browserify": { + "version": "https://registry.npmjs.org/zlib-browserify/-/zlib-browserify-0.0.1.tgz", + "integrity": "sha1-T6akXQDbwV8xikr6HZr8Aljhdsw=", + "dev": true + }, + "zrender": { + "version": "https://registry.npmjs.org/zrender/-/zrender-3.5.2.tgz", + "integrity": "sha1-53DL6Xi19JgcG5PZuEFHo0dPIdI=" + } + } +} diff --git a/package.json b/package.json index 80d6ed2cd..26005cc38 100644 --- a/package.json +++ b/package.json @@ -53,5 +53,11 @@ "protractor": "protractor test/protractor-conf.js", "update-index-async": "node -e \"require('shelljs/global'); sed('-i', /\\/\\/@@NG_LOADER_START@@[\\s\\S]*\\/\\/@@NG_LOADER_END@@/, '//@@NG_LOADER_START@@\\n' + cat('bower_components/angular-loader/angular-loader.min.js') + '\\n//@@NG_LOADER_END@@', 'app/index-async.html');\"" }, - "dependencies": {} + "dependencies": { + "echarts": "^3.5.4", + "echarts-gl": "^1.0.0-alpha.6", + "echarts-liquidfill": "^1.0.5", + "echarts-wordcloud": "^1.0.3", + "gojs": "^1.7.14" + } } diff --git a/src/META-INF/MANIFEST.MF b/src/META-INF/MANIFEST.MF new file mode 100644 index 000000000..d3cf42f2b --- /dev/null +++ b/src/META-INF/MANIFEST.MF @@ -0,0 +1,4 @@ +Manifest-Version: 1.0 +Ant-Version: Apache Ant 1.9.4 +Created-By: 1.8.0_45-b15 (Oracle Corporation) + diff --git a/src/WEB-INF/web.xml b/src/WEB-INF/web.xml index 814af5220..be9982eb6 100644 --- a/src/WEB-INF/web.xml +++ b/src/WEB-INF/web.xml @@ -5,7 +5,7 @@ http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> - Banana Web Application + RealSight APM Realtime Dashboard index.html diff --git a/src/app/app.js b/src/app/app.js old mode 100755 new mode 100644 index 21ce321fb..3d3a402af --- a/src/app/app.js +++ b/src/app/app.js @@ -2,178 +2,174 @@ * main app level module */ define([ - 'angular', - 'jquery', - 'underscore', - 'require', - - 'elasticjs', - 'solrjs', - 'bootstrap', - 'angular-sanitize', - 'angular-strap', - 'angular-dragdrop', - 'extend-jquery' -], -function (angular, $, _, appLevelRequire) { - "use strict"; - - var app = angular.module('kibana', []), - // we will keep a reference to each module defined before boot, so that we can - // go back and allow it to define new features later. Once we boot, this will be false - pre_boot_modules = [], - // these are the functions that we need to call to register different - // features if we define them after boot time - register_fns = {}; - - /** - * Tells the application to watch the module, once bootstraping has completed - * the modules controller, service, etc. functions will be overwritten to register directly - * with this application. - * @param {[type]} module [description] - * @return {[type]} [description] - */ - app.useModule = function (module) { - if (pre_boot_modules) { - pre_boot_modules.push(module); - } else { - _.extend(module, register_fns); - } - return module; - }; - - app.safeApply = function ($scope, fn) { - switch($scope.$$phase) { - case '$apply': - // $digest hasn't started, we should be good - $scope.$eval(fn); - break; - case '$digest': - // waiting to $apply the changes - setTimeout(function () { app.safeApply($scope, fn); }, 10); - break; - default: - // clear to begin an $apply $$phase - $scope.$apply(fn); - break; + 'angular', + 'jquery', + 'underscore', + 'require', + 'cookies', + 'elasticjs', + 'solrjs', + 'bootstrap', + 'angular-sanitize', + 'angular-strap', + 'angular-dragdrop', + 'angular-route', + 'angular-material', + 'angular-smart-table', + 'extend-jquery', + ], + function (angular, $, _, appLevelRequire) { + "use strict"; + var username = $.cookie('rtd_username'); + var password = $.cookie('rtd_password'); + var realUsername = ""; + var realPassword = ""; + $.ajaxSettings.async = false; + $.getJSON('assets/json/login.json', function(data){ + realUsername =data.username; + realPassword = data.password; + }); + $.ajaxSettings.async = true; + //var a = sessionStorage.getItem(realUsername); + //if(username==realUsername&&password==realPassword){ + //self.current.headHide = false; + + // if(typeof(username)=="undefined"){ + // window.location.href = window.location.origin+window.location.pathname+"login.html"; + // } + if(username!==realUsername||password!==realPassword){ + + sessionStorage.setItem("goalUrl",window.location.hash); + + window.location.href = window.location.origin+window.location.pathname.replace("index.html","")+"login.html"; } - }; - - app.config(function ($routeProvider, $controllerProvider, $compileProvider, $filterProvider, $provide) { - $routeProvider - .when('/dashboard', { - templateUrl: 'app/partials/dashboard.html', - }) - .when('/dashboard/:kbnType/:kbnId', { - templateUrl: 'app/partials/dashboard.html', - }) - .when('/dashboard/:kbnType/:kbnId/:params', { - templateUrl: 'app/partials/dashboard.html' - }) - .otherwise({ - redirectTo: 'dashboard' - }); - // this is how the internet told me to dynamically add modules :/ - register_fns.controller = $controllerProvider.register; - register_fns.directive = $compileProvider.directive; - register_fns.factory = $provide.factory; - register_fns.service = $provide.service; - register_fns.filter = $filterProvider.register; - }); + var app = angular.module('kibana', ['ngRoute', 'ngSanitize']), + // we will keep a reference to each module defined before boot, so that we can + // go back and allow it to define new features later. Once we boot, this will be false + pre_boot_modules = [], + // these are the functions that we need to call to register different + // features if we define them after boot time + register_fns = {}; - // $http requests in Angular 1.0.x include the 'X-Requested-With' header - // which triggers the preflight request in CORS. This does not work as - // Solr rejects the preflight request, so I have to remove the header. - // NOTE: The 'X-Requested-With' header has been removed in Angular 1.1.x - app.config(['$httpProvider', function($httpProvider) { - $httpProvider.defaults.useXDomain = true; - delete $httpProvider.defaults.headers.common["X-Requested-With"]; - // If the backend (apollo) gives us a 401, redirect to the login page. - $httpProvider.responseInterceptors.push(function() { - return function(p){ - return p.then( - angular.identity, - function(err){ - if( err.status === 401 ){ - // Send in the current location for a post login redirect - // -- the "return" param. - // Do this as a relative path change since we don't know what - // the base/root path will be, we do know banana will always be - // served by the proxy at $root/banana/ - login is 1 level up. - var query = window.location.search, - hash = window.location.hash, - goto = '../login?return=' + window.location.pathname; - goto += (hash ? hash : ""); - goto += (query ? "?" + encodeURIComponent(query) : ""); - goto = goto.replace(/#/g, '%23'); - window.location = goto; - return; - } else if (err.status === 404) { - console.log('http 404 encounter!'); - } - } - ); - }; - // }]); + /** + * Tells the application to watch the module, once bootstraping has completed + * the modules controller, service, etc. functions will be overwritten to register directly + * with this application. + * @param {[type]} module [description] + * @return {[type]} [description] + */ + app.useModule = function (module) { + if (pre_boot_modules) { + pre_boot_modules.push(module); + } else { + _.extend(module, register_fns); + } + return module; + }; + + app.safeApply = function ($scope, fn) { + switch($scope.$$phase) { + case '$apply': + // $digest hasn't started, we should be good + $scope.$eval(fn); + break; + case '$digest': + // waiting to $apply the changes + setTimeout(function () { app.safeApply($scope, fn); }, 10); + break; + default: + // clear to begin an $apply $$phase + $scope.$apply(fn); + break; + } + }; + + app.config(function ($routeProvider, $controllerProvider, $compileProvider, $filterProvider, $provide) { + $routeProvider + .when('/dashboard', { + templateUrl: 'app/partials/dashboard.html', + }) + .when('/dashboard/:kbnType/:kbnId', { + templateUrl: 'app/partials/dashboard.html', + }) + .when('/dashboard/:kbnType/:kbnId/:params', { + templateUrl: 'app/partials/dashboard.html' + }) + .when('/alarm', { + templateUrl: 'app/partials/alarm.html' + }) + .otherwise({ + redirectTo: 'dashboard' + }); + // this is how the internet told me to dynamically add modules :/ + register_fns.controller = $controllerProvider.register; + register_fns.directive = $compileProvider.directive; + register_fns.factory = $provide.factory; + register_fns.service = $provide.service; + register_fns.filter = $filterProvider.register; }); - }]); - - var apps_deps = [ - 'elasticjs.service', - 'solrjs.service', - '$strap.directives', - 'ngSanitize', - 'ngDragDrop', - 'kibana' - ]; - - _.each('controllers directives factories services filters'.split(' '), - function (type) { - var module_name = 'kibana.'+type; - // create the module - app.useModule(angular.module(module_name, [])); - // push it into the apps dependencies - apps_deps.push(module_name); - }); - app.panel_helpers = { - partial: function (name) { - return 'app/partials/'+name+'.html'; - } - }; - - // load the core components - require([ - 'controllers/all', - 'directives/all', - 'filters/all' - ], function () { - - // bootstrap the app - angular - .element(document) - .ready(function() { - $('body').attr('ng-controller', 'DashCtrl'); - angular.bootstrap(document, apps_deps) - .invoke(['$rootScope', function ($rootScope) { - _.each(pre_boot_modules, function (module) { - _.extend(module, register_fns); - }); - pre_boot_modules = false; - - $rootScope.requireContext = appLevelRequire; - $rootScope.require = function (deps, fn) { - var $scope = this; - $scope.requireContext(deps, function () { - var deps = _.toArray(arguments); - $scope.$apply(function () { - fn.apply($scope, deps); - }); - }); - }; - }]); + + var apps_deps = [ + 'elasticjs.service', + 'solrjs.service', + '$strap.directives', + 'ngSanitize', + 'ngDragDrop', + 'ngMaterial', + 'smart-table', + 'kibana', + ]; + + _.each('controllers directives factories services filters alarms'.split(' '), + function (type) { + var module_name = 'kibana.'+type; + // create the module + app.useModule(angular.module(module_name, [])); + // push it into the apps dependencies + apps_deps.push(module_name); }); - }); - return app; -}); + + + app.panel_helpers = { + partial: function (name) { + return 'app/partials/'+name+'.html'; + } + }; + + // load the core components + require([ + 'controllers/all', + 'directives/all', + 'filters/all', + ], function () { + + // bootstrap the app + angular + .element(document) + .ready(function() { + $('body').attr('ng-controller', 'DashCtrl'); + angular.bootstrap(document, apps_deps) + .invoke(['$rootScope', function ($rootScope) { + _.each(pre_boot_modules, function (module) { + _.extend(module, register_fns); + }); + pre_boot_modules = false; + + $rootScope.requireContext = appLevelRequire; + $rootScope.require = function (deps, fn) { + var $scope = this; + $scope.requireContext(deps, function () { + var deps = _.toArray(arguments); + $scope.$apply(function () { + fn.apply($scope, deps); + }); + }); + }; + }]); + }); + }); + + return app; + }); diff --git a/src/app/components/extend-jquery.js b/src/app/components/extend-jquery.js old mode 100755 new mode 100644 diff --git a/src/app/components/kbn.js b/src/app/components/kbn.js old mode 100755 new mode 100644 diff --git a/src/app/components/require.config.js b/src/app/components/require.config.js old mode 100755 new mode 100644 index 5c11bffbf..e3a3c4d7f --- a/src/app/components/require.config.js +++ b/src/app/components/require.config.js @@ -3,7 +3,6 @@ */ require.config({ baseUrl: 'app', - waitSeconds: 0, // urlArgs: 'r=@REV@', paths: { config: '../config', @@ -15,10 +14,18 @@ require.config({ moment: '../vendor/moment', filesaver: '../vendor/filesaver', - angular: '../vendor/angular/angular', - 'angular-dragdrop': '../vendor/angular/angular-dragdrop', + angular: '../../bower_components/angular/angular', + 'angular-dragdrop': '../../bower_components/angular-dragdrop/src/angular-dragdrop', 'angular-strap': '../vendor/angular/angular-strap', - 'angular-sanitize': '../vendor/angular/angular-sanitize', + 'angular-sanitize': '../../bower_components/angular-sanitize/angular-sanitize', + 'angular-route': '../../bower_components/angular-route/angular-route', + 'angular-aria': '../../bower_components/angular-aria/angular-aria', + 'angular-animate': '../../bower_components/angular-animate/angular-animate', + 'angular-material': '../../bower_components/angular-material/angular-material', + 'angular-smart-table': '../../bower_components/angular-smart-table/dist/smart-table', + //'angular-translate.min': '../vendor/angular/angular-translate.min', + //'angular-translate-loader-static-files': '../vendor/angular/angular-translate-loader-static-files', + timepicker: '../vendor/angular/timepicker', datepicker: '../vendor/angular/datepicker', @@ -27,6 +34,7 @@ require.config({ bootstrap: '../vendor/bootstrap/bootstrap', jquery: '../vendor/jquery/jquery-1.12.1', + cookies: '../vendor/jquery/jquery.cookie', 'jquery-ui': '../vendor/jquery/jquery-ui-1.10.3', 'extend-jquery': 'components/extend-jquery', @@ -40,10 +48,40 @@ require.config({ 'jquery.flot.axislabels': '../vendor/jquery/jquery.flot.axislabels', 'showdown': '../vendor/showdown', + echarts: '../../node_modules/echarts/dist/echarts', + 'echarts-gl': '../../node_modules/echarts-gl/dist/echarts-gl', + 'echarts-liquidfill': '../../node_modules/echarts-liquidfill/dist/echarts-liquidfill', + 'echarts-wordcloud': '../../node_modules/echarts-wordcloud/dist/echarts-wordcloud', + 'echarts-bmap': '../../node_modules/echarts/dist/extension/bmap', + 'echarts-china': '../../node_modules/echarts/map/js/china', + modernizr: '../vendor/modernizr-2.6.1', elasticjs: '../vendor/elasticjs/elastic-angular-client', solrjs: '../vendor/solrjs/solr-angular-client', - d3: '../vendor/d3' + + d3: '../../bower_components/d3/d3', + viz: '../vendor/viz.v1.0.0.min', + Donut3D: '../vendor/d3/Donut3D', + html2canvas: '../../bower_components/html2canvas/build/html2canvas', + jspdf: '../../bower_components/jspdf/dist/jspdf.min', + gojs: '../../src/vendor/go' + /* + d3: '../vendor/d3', + viz: '../vendor/viz.v1.0.0.min', + kagi: '../vendor/kagi', + bubble: '../vendor/d3/bubble-chart', + centralclick: '../vendor/d3/central-click', + d3transform: '../vendor/d3/d3-transform', + extarray: '../vendor/d3/extarray', + lines: '../vendor/d3/lines', + microobserver: '../vendor/d3/micro-observer', + microplugin: '../vendor/d3/microplugin', + misc: '../vendor/d3/misc', + d3min: '../vendor/d3/d3.min', + jquerymin: '../vendor/d3/jquery.min', + Donut3D: '../vendor/d3/Donut3D', + bullet: '../vendor/d3/bullet', + */ }, shim: { underscore: { @@ -74,8 +112,8 @@ require.config({ 'jquery.flot.selection':['jquery', 'jquery.flot'], 'jquery.flot.stack': ['jquery', 'jquery.flot'], 'jquery.flot.stackpercent':['jquery', 'jquery.flot'], - 'jquery.flot.time': ['jquery', 'jquery.flot'], - 'jquery.flot.axislabels': ['jquery', 'jquery.flot'], + 'jquery.flot.time': ['jquery', 'jquery.flot'], + 'jquery.flot.axislabels':['jquery', 'jquery.flot'], 'angular-sanitize': ['angular'], 'angular-cookies': ['angular'], @@ -83,15 +121,21 @@ require.config({ 'angular-loader': ['angular'], 'angular-mocks': ['angular'], 'angular-resource': ['angular'], - 'angular-route': ['angular'], + 'angular-aria': ['angular'], + 'angular-animate': ['angular'], + 'angular-material': ['angular', 'angular-aria', 'angular-animate'], 'angular-touch': ['angular'], - + 'angular-route': ['angular'], 'angular-strap': ['angular', 'bootstrap','timepicker', 'datepicker'], + 'angular-smart-table': ['angular'], timepicker: ['jquery', 'bootstrap'], datepicker: ['jquery', 'bootstrap'], elasticjs: ['angular', '../vendor/elasticjs/elastic'], - solrjs: ['angular', '../vendor/solrjs/solr'] + solrjs: ['angular', '../vendor/solrjs/solr'], + Donut3D: ['d3'], + 'echarts-liquidfill': ['echarts'], + 'viz': ['d3'], } }); diff --git a/src/app/components/settings.js b/src/app/components/settings.js old mode 100755 new mode 100644 index 76e9974a2..3ed8613c2 --- a/src/app/components/settings.js +++ b/src/app/components/settings.js @@ -10,29 +10,13 @@ function (_) { * @type {Object} */ var defaults = { - solr: "http://"+window.location.hostname+":8983/solr/", - solr_core: "logs", - timefield: "timestamp_tdt", + solr: "http://"+window.location.hostname+":9983/solr/", + solr_core: "apm3", + timefield: 'rs_timestamp', + banana_index : 'banana-int', USE_ADMIN_LUKE: true, USE_ADMIN_CORES: true, - panel_names: [], - banana_index: "system_banana", - - // Lucidworks Fusion settings - USE_FUSION: true, - apollo: "/api/apollo", - apollo_queryPipeline: "/api/apollo/query-pipelines/", - apollo_indexPipeline: "/api/apollo/index-pipelines/", - - SYSTEM_BANANA_QUERY_PIPELINE: "/api/apollo/query-pipelines/default/collections/system_banana", - SYSTEM_BANANA_INDEX_PIPELINE: "/api/apollo/index-pipelines/_system/collections/system_banana", - SYSTEM_BANANA_BLOB_API: "/api/apollo/blobs", - SYSTEM_BANANA_BLOB_ID_SUBTYPE_PARAM: "resourceType=banana", // for use when saving dashboards, to create metadata field resourceType=banana - SYSTEM_BANANA_BLOB_ID_SUBTYPE_QUERY: "resourceType=banana", // for use when searching dashboards in Blob Store - - FUSION_API_STATIC_FIELDS: "/schema/fields", - FUSION_API_DYNAMIC_FIELDS: "/schema/dynamicfields", - FUSION_API_COLLECTIONS: "/api/apollo/collections" + panel_names : [], }; // This initializes a new hash on purpose, to avoid adding parameters to diff --git a/src/app/components/underscore.extended.js b/src/app/components/underscore.extended.js old mode 100755 new mode 100644 diff --git a/src/app/controllers/all.js b/src/app/controllers/all.js old mode 100755 new mode 100644 index 8dfca49d7..fdfa06266 --- a/src/app/controllers/all.js +++ b/src/app/controllers/all.js @@ -2,4 +2,5 @@ define([ './dash', './dashLoader', './row', + //'./language', ], function () {}); \ No newline at end of file diff --git a/src/app/controllers/dash.js b/src/app/controllers/dash.js old mode 100755 new mode 100644 index 8ac5c1a53..406ec6d16 --- a/src/app/controllers/dash.js +++ b/src/app/controllers/dash.js @@ -1,90 +1,91 @@ define([ - 'angular', - 'config', - 'underscore', - 'services/all' + 'angular', + 'config', + 'underscore', + 'services/all' ], function (angular, config, _) { - "use strict"; + "use strict"; - var module = angular.module('kibana.controllers'); + var module = angular.module('kibana.controllers'); - module.controller('DashCtrl', function ($scope, $route, ejsResource, sjsResource, fields, dashboard, alertSrv, panelMove) { - $scope.editor = { - index: 0 - }; + module.controller('DashCtrl', function( + $scope, $route, ejsResource, sjsResource, fields, dashboard, alertSrv, panelMove) { + $scope.editor = { + index: 0 + }; - // For moving stuff around the dashboard. Needs better names - $scope.panelMove = panelMove; - $scope.panelMoveDrop = panelMove.onDrop; - $scope.panelMoveStart = panelMove.onStart; - $scope.panelMoveStop = panelMove.onStop; - $scope.panelMoveOver = panelMove.onOver; - $scope.panelMoveOut = panelMove.onOut; + // For moving stuff around the dashboard. Needs better names + $scope.panelMove = panelMove; + $scope.panelMoveDrop = panelMove.onDrop; + $scope.panelMoveStart = panelMove.onStart; + $scope.panelMoveStop = panelMove.onStop; + $scope.panelMoveOver = panelMove.onOver; + $scope.panelMoveOut = panelMove.onOut; - $scope.init = function () { - $scope.config = config; - // Make underscore.js available to views - $scope._ = _; - $scope.dashboard = dashboard; - $scope.dashAlerts = alertSrv; - alertSrv.clearAll(); + $scope.init = function() { + $scope.config = config; + // Make underscore.js available to views + $scope._ = _; + $scope.dashboard = dashboard; + $scope.dashAlerts = alertSrv; + alertSrv.clearAll(); - // Provide a global list of all see fields - $scope.fields = fields; - $scope.reset_row(); + // Provide a global list of all see fields + $scope.fields = fields; + $scope.reset_row(); - // Solr - $scope.ejs = ejsResource(config.elasticsearch); - $scope.sjs = sjsResource(config.solr + config.solr_core); - }; + // Solr + $scope.ejs = ejsResource(config.elasticsearch); + $scope.sjs = sjsResource(config.solr + config.solr_core); + }; - $scope.isPanel = function (obj) { - if (!_.isNull(obj) && !_.isUndefined(obj) && !_.isUndefined(obj.type)) { - return true; - } else { - return false; - } - }; + $scope.isPanel = function(obj) { + if(!_.isNull(obj) && !_.isUndefined(obj) && !_.isUndefined(obj.type)) { + return true; + } else { + return false; + } + }; - $scope.add_row = function (dash, row) { - dash.rows.push(row); - }; + $scope.add_row = function(dash,row) { + dash.rows.push(row); + }; - $scope.reset_row = function () { - $scope.row = { - title: '', - height: '150px', - editable: true, - }; - }; + $scope.reset_row = function() { + $scope.row = { + title: '', + height: '150px', + editable: true, + }; + }; - $scope.row_style = function (row) { - return {'min-height': row.collapse ? '5px' : row.height}; - }; + $scope.row_style = function(row) { + return { 'min-height': row.collapse ? '5px' : row.height }; + }; - $scope.edit_path = function (type) { - if (type) { - return 'app/panels/' + type + '/editor.html'; - } else { - return false; - } - }; + $scope.edit_path = function(type) { + if(type) { + return 'app/panels/'+type+'/editor.html'; + } else { + return false; + } + }; - $scope.setEditorTabs = function (panelMeta) { - $scope.editorTabs = ['General', 'Panel', 'Info']; - if (!_.isUndefined(panelMeta.editorTabs)) { - $scope.editorTabs = _.union($scope.editorTabs, _.pluck(panelMeta.editorTabs, 'title')); - } - return $scope.editorTabs; - }; + $scope.setEditorTabs = function(panelMeta) { + $scope.editorTabs = ['General','Panel','Info']; + if(!_.isUndefined(panelMeta.editorTabs)) { + $scope.editorTabs = _.union($scope.editorTabs,_.pluck(panelMeta.editorTabs,'title')); + } + return $scope.editorTabs; + }; - // This is whoafully incomplete, but will do for now - $scope.parse_error = function (data) { - var _error = data.match("nested: (.*?);"); - return _.isNull(_error) ? data : _error[1]; - }; + // This is whoafully incomplete, but will do for now + $scope.parse_error = function(data) { + var _error = data.match("nested: (.*?);"); + return _.isNull(_error) ? data : _error[1]; + }; - $scope.init(); - }); -}); + $scope.init(); + }); +}); \ No newline at end of file diff --git a/src/app/controllers/dashLoader.js b/src/app/controllers/dashLoader.js old mode 100755 new mode 100644 index a343bf03c..8fd9bb6b9 --- a/src/app/controllers/dashLoader.js +++ b/src/app/controllers/dashLoader.js @@ -1,339 +1,180 @@ define([ - 'angular', - 'underscore', - 'config' + 'angular', + 'underscore' ], -function (angular, _, config) { - 'use strict'; - - var module = angular.module('kibana.controllers'); - - module.controller('dashLoader', function ($scope, $http, timer, dashboard, alertSrv) { - var self = this; - // Solr and Fusion uses different field names for their schema. - // Solr uses banana-int collection, and Fusion uses system_banana collection. - self.TITLE_FIELD = 'title'; - self.DASHBOARD_FIELD = 'dashboard'; - self.USER_FIELD = 'user'; - self.GROUP_FIELD = 'group'; - - // NOTES: Fusion uses Blob Store API now, so it does not need TITLE_FIELD for querying dashboards. - // If USE_FUSION, change the schema field names and banana_index setting. - // Also, get the login username and store it. - if (config.USE_FUSION) { - config.banana_index = 'system_banana'; - self.TITLE_FIELD = 'banana_title_s'; - self.DASHBOARD_FIELD = 'banana_dashboard_s'; - self.USER_FIELD = 'banana_user_s'; - self.GROUP_FIELD = 'banana_group_s'; - } - - $scope.getTitleField = function getTitleField() { - return self.TITLE_FIELD; - }; - - $scope.loader = dashboard.current.loader; - - $scope.init = function () { - $scope.gist_pattern = /(^\d{5,}$)|(^[a-z0-9]{10,}$)|(gist.github.com(\/*.*)\/[a-z0-9]{5,}\/*$)/; - $scope.gist = $scope.gist || {}; - $scope.elasticsearch = $scope.elasticsearch || {}; - $scope.resetNewDefaults(); - // $scope.elasticsearch is used throught out this file, dashLoader.html and others. - // So we'll keep using it for now before refactoring it to $scope.solr. - // $scope.solr = $scope.solr || {}; - - // Pagination - $scope.loadMenu = { - currentPage: 1, // Current active page in the pager. - firstPageShown: 1, // First page number that is shown in the pager. - lastPageShown: 5, // Last page number that is shown in the pager. - totalPages: 5, // total number of pages needed to display all saved dashboards: - // = Math.ceil(total_num_of_saved_dashboards / dashboard.current.loader.load_elasticsearch_size) - maxShownPages: 5, // Hard coded value. The maximum number of pages to be shown in the pager. - pages: [], // Example pages obj => {offset: 0, number: 1, state: 'active'} - backwardButtonState: 'disabled', - forwardButtonState: 'disabled' - }; - - $scope.elasticsearch.query = ''; // query for filtering the dashboard list - }; - - // This function should be replaced by one-way binding feature of AngularJS 1.3 - $scope.resetNewDefaults = function () { - $scope.new = { - server: $scope.config.solr, - core_name: $scope.config.solr_core, - time_field: $scope.config.timefield, - USE_FUSION: $scope.config.USE_FUSION - }; - }; - - $scope.showDropdown = function (type) { - // var _l = $scope.loader; - var _l = dashboard.current.loader || $scope.loader; - - if (type === 'new') { - return (_l.load_elasticsearch || _l.load_gist || _l.load_local); - } - if (type === 'load') { - return (_l.load_elasticsearch || _l.load_gist || _l.load_local); - } - if (type === 'save') { - return (_l.save_elasticsearch || _l.save_gist || _l.save_local || _l.save_default); - } - if (type === 'share') { - return (_l.save_temp); - } - if(type === 'home') { - return (dashboard.current.home || $scope.home); - } - - return false; - }; - - $scope.create_new = function (type) { - $http.get('app/dashboards/' + type + '.json?' + new Date().getTime()).success(function (data) { - data.solr.server = $scope.new.server; - data.solr.core_name = $scope.new.core_name; - // If time series dashboard, update all timefield references in the default dashboard - if (type === 'default-ts') { - data.services.filter.list[0].field = $scope.new.time_field; - // Iterate over panels and update timefield - for (var i = 0; i < data.rows.length; i++) { - for (var j = 0; j < data.rows[i].panels.length; j++) { - if (data.rows[i].panels[j].timefield) { - data.rows[i].panels[j].timefield = $scope.new.time_field; - } else if (data.rows[i].panels[j].time_field) { - data.rows[i].panels[j].time_field = $scope.new.time_field; - } - } - } - } - - dashboard.dash_load(data); - - // Reset new dashboard defaults - $scope.resetNewDefaults(); - }).error(function () { - alertSrv.set('Error', 'Unable to load default dashboard', 'error'); - }); - }; - - $scope.set_default = function () { - if (dashboard.set_default()) { - alertSrv.set('Local Default Set', dashboard.current.title + ' has been set as your local default', 'success', 5000); - } else { - alertSrv.set('Incompatible Browser', 'Sorry, your browser is too old for this feature', 'error', 5000); - } - }; - - $scope.purge_default = function () { - if (dashboard.purge_default()) { - alertSrv.set('Local Default Clear', 'Your local default dashboard has been cleared', 'success', 5000); - } else { - alertSrv.set('Incompatible Browser', 'Sorry, your browser is too old for this feature', 'error', 5000); - } - }; - - $scope.elasticsearch_save = function (type, ttl) { - dashboard.elasticsearch_save( - type, - ($scope.elasticsearch.title || dashboard.current.title), - ($scope.loader.save_temp_ttl_enable ? ttl : false) - ).then(function (result) { - alertSrv.set('Dashboard Saved', 'This dashboard has been saved to Solr as "' + - ($scope.elasticsearch.title || dashboard.current.title) + '"', 'success', 5000); - if (type === 'temp') { - $scope.share = dashboard.share_link(dashboard.current.title, 'temp', result.response.docs[0].id); - } - $scope.elasticsearch.title = ''; - }, function (error) { - console.log('ERROR: ' + error); - alertSrv.set('Save failed', 'Dashboard could not be saved to Solr', 'error', 5000); - }); - }; - - $scope.elasticsearch_delete = function (id) { - dashboard.elasticsearch_delete(id).then( - function (result) { - if (config.USE_FUSION) { - // The result returned from Blob Store API (DELETE request) will be an empty string. - // Need to return the result in Solr json format. - result = { - responseHeader: {status: 0} - }; - } - - if (!_.isUndefined(result)) { - if (result.responseHeader.status === 0) { - alertSrv.set('Dashboard Deleted', id + ' has been deleted', 'success', 5000); - // Find the deleted dashboard in the cached list and remove it - var toDelete = _.where($scope.elasticsearch.dashboards, {id: id})[0]; - $scope.elasticsearch.dashboards = _.without($scope.elasticsearch.dashboards, toDelete); - } else { - alertSrv.set('Dashboard Not Found', 'Could not find ' + id + ' in Solr', 'warning', 5000); - } - } else { - alertSrv.set('Dashboard Not Deleted', 'An error occurred deleting the dashboard', 'error', 5000); - } +function (angular, _) { + 'use strict'; + + var module = angular.module('kibana.controllers'); + + module.controller('dashLoader', function($scope, $http, timer, dashboard, alertSrv) { + $scope.loader = dashboard.current.loader; + + $scope.init = function() { + $scope.gist_pattern = /(^\d{5,}$)|(^[a-z0-9]{10,}$)|(gist.github.com(\/*.*)\/[a-z0-9]{5,}\/*$)/; + $scope.gist = $scope.gist || {}; + $scope.elasticsearch = $scope.elasticsearch || {}; + $scope.resetNewDefaults(); + // $scope.elasticsearch is used throught out this file, dashLoader.html and others. + // So we'll keep using it for now before refactoring it to $scope.solr. + // $scope.solr = $scope.solr || {}; + }; + + // This function should be replaced by one-way binding feature of AngularJS 1.3 + $scope.resetNewDefaults = function() { + $scope.new = { + server: $scope.config.solr, + core_name: $scope.config.solr_core, + time_field: $scope.config.timefield + }; + }; + + $scope.showDropdown = function(type) { + // var _l = $scope.loader; + var _l = dashboard.current.loader || $scope.loader; + + if(type === 'new') { + return (_l.load_elasticsearch || _l.load_gist || _l.load_local); + } + if(type === 'load') { + return (_l.load_elasticsearch || _l.load_gist || _l.load_local); + } + if(type === 'save') { + return (_l.save_elasticsearch || _l.save_gist || _l.save_local || _l.save_default); + } + if(type === 'share') { + return (_l.save_temp); + } + return false; + }; + + $scope.create_new = function(type) { + $http.get('app/dashboards/' + type + '.json?' + new Date().getTime()). + success(function(data) { + data.solr.server = $scope.new.server; + data.solr.core_name = $scope.new.core_name; + // If time series dashboard, update all timefield references in the default dashboard + if (type === 'default-ts') { + data.services.filter.list[0].field = $scope.new.time_field; + // Iterate over panels and update timefield + for (var i = 0; i < data.rows.length; i++) { + for (var j = 0; j < data.rows[i].panels.length; j++) { + if (data.rows[i].panels[j].timefield) { + data.rows[i].panels[j].timefield = $scope.new.time_field; + } else if (data.rows[i].panels[j].time_field) { + data.rows[i].panels[j].time_field = $scope.new.time_field; } - ); - }; - - $scope.elasticsearch_dblist = function (query) { - dashboard.elasticsearch_list(query, dashboard.current.loader.load_elasticsearch_size).then( - function (result) { - if (!_.isUndefined(result.response.docs)) { - $scope.hits = result.response.numFound; - $scope.elasticsearch.dashboards = parseDashboardList(result.response.docs); - - // Handle pagination - $scope.loadMenu.totalPages = Math.ceil($scope.hits / dashboard.current.loader.load_elasticsearch_size); - var pages = []; - for (var j = 0; j < $scope.loadMenu.totalPages; j++) { - pages.push({ - offset: j * dashboard.current.loader.load_elasticsearch_size, - number: j + 1, - state: '' - }); - } - - $scope.loadMenu.pages = pages; - $scope.loadMenu.currentPage = 1; - if ($scope.loadMenu.pages.length > 0) { - $scope.loadMenu.pages[0].state = 'active'; - } - - if ($scope.loadMenu.totalPages > $scope.loadMenu.maxShownPages) { - $scope.loadMenu.forwardButtonState = ''; - } else { - $scope.loadMenu.forwardButtonState = 'disabled'; - $scope.loadMenu.backwardButtonState = 'disabled'; - } - } - }); - }; - - // Get the dashboard list for the specified pageNum - $scope.getSavedDashboard = function (event, query, offset, pageNum) { - // To stop dropdown-menu from disappearing after click - event.stopPropagation(); - - // Fusion uses Blob Store API, so Solr query will not work here. - if (config.USE_FUSION) { - query = query || ''; - } else { - // TODO: getTitleField() + ':' + elasticsearch.query + '*' - // query += '&start=' + offset; - query = $scope.getTitleField() + ':' + query + '*&start=' + offset; - } - - dashboard.elasticsearch_list(query, dashboard.current.loader.load_elasticsearch_size).then( - function (result) { - if (!_.isUndefined(result.response.docs)) { - $scope.hits = result.response.numFound; - // Get the list according to pageNum (paging). - var startIndex = offset; - var endIndex = offset + dashboard.current.loader.load_elasticsearch_size; - $scope.elasticsearch.dashboards = parseDashboardList(result.response.docs).slice(startIndex, endIndex); - } - } - ); - - if (pageNum >= 1) { - $scope.loadMenu.pages[$scope.loadMenu.currentPage-1].state = ''; - $scope.loadMenu.pages[pageNum-1].state = 'active'; - $scope.loadMenu.currentPage = pageNum; + } } - }; - - $scope.getPrevSavedDashboard = function (event) { - // To stop dropdown-menu from disappearing after click - event.stopPropagation(); - - if ($scope.loadMenu.firstPageShown !== 1) { - var newFirstPage = $scope.loadMenu.firstPageShown - $scope.loadMenu.maxShownPages; - $scope.loadMenu.forwardButtonState = ''; - - if (newFirstPage <= 1) { - $scope.loadMenu.firstPageShown = 1; - $scope.loadMenu.lastPageShown = $scope.loadMenu.maxShownPages; - $scope.loadMenu.backwardButtonState = 'disabled'; - } else { - $scope.loadMenu.firstPageShown = newFirstPage; - $scope.loadMenu.lastPageShown = newFirstPage + $scope.loadMenu.maxShownPages - 1; - } - } else { - $scope.loadMenu.backwardButtonState = 'disabled'; - } - }; - - $scope.getNextSavedDashboard = function (event) { - // To stop dropdown-menu from disappearing after click - event.stopPropagation(); - - if ($scope.loadMenu.lastPageShown !== $scope.loadMenu.totalPages) { - var newLastPage = $scope.loadMenu.lastPageShown + $scope.loadMenu.maxShownPages; - $scope.loadMenu.firstPageShown = $scope.loadMenu.lastPageShown + 1; - $scope.loadMenu.backwardButtonState = ''; - - if (newLastPage >= $scope.loadMenu.totalPages) { - $scope.loadMenu.lastPageShown = $scope.loadMenu.totalPages; - $scope.loadMenu.forwardButtonState = 'disabled'; - } else { - $scope.loadMenu.lastPageShown = newLastPage; - } + } + + dashboard.dash_load(data); + + // Reset new dashboard defaults + $scope.resetNewDefaults(); + }). + error(function() { + alertSrv.set('Error','Unable to load default dashboard','error'); + }); + }; + + $scope.set_default = function() { + if(dashboard.set_default()) { + alertSrv.set('Local Default Set',dashboard.current.title+' has been set as your local default','success',5000); + } else { + alertSrv.set('Incompatible Browser','Sorry, your browser is too old for this feature','error',5000); + } + }; + + $scope.purge_default = function() { + if(dashboard.purge_default()) { + alertSrv.set('Local Default Clear','Your local default dashboard has been cleared','success',5000); + } else { + alertSrv.set('Incompatible Browser','Sorry, your browser is too old for this feature','error',5000); + } + }; + + $scope.elasticsearch_save = function(type,ttl) { + dashboard.elasticsearch_save( + type, + ($scope.elasticsearch.title || dashboard.current.title), + ($scope.loader.save_temp_ttl_enable ? ttl : false) + ).then( + function(result) { + // Solr + if(result.responseHeader.status === 0) { + alertSrv.set('Dashboard Saved','This dashboard has been saved to Solr as "' + + ($scope.elasticsearch.title || dashboard.current.title) + '"','success',5000); + if(type === 'temp') { + $scope.share = dashboard.share_link(dashboard.current.title,'temp',result.response.docs[0].id); + } + $scope.elasticsearch.title = ''; + } else { + alertSrv.set('Save failed','Dashboard could not be saved to Solr','error',5000); + } + }); + }; + + $scope.elasticsearch_delete = function(id) { + dashboard.elasticsearch_delete(id).then( + function(result) { + if(!_.isUndefined(result)) { + if (result.responseHeader.status === 0) { + alertSrv.set('Dashboard Deleted',id+' has been deleted','success',5000); + // Find the deleted dashboard in the cached list and remove it + // var toDelete = _.where($scope.elasticsearch.dashboards,{_id:id})[0]; + var toDelete = _.where($scope.elasticsearch.dashboards,{id:id})[0]; + $scope.elasticsearch.dashboards = _.without($scope.elasticsearch.dashboards,toDelete); } else { - $scope.loadMenu.forwardButtonState = 'disabled'; + alertSrv.set('Dashboard Not Found','Could not find '+id+' in Solr','warning',5000); } - }; - - $scope.save_gist = function () { - dashboard.save_gist($scope.gist.title).then( - function (link) { - if (!_.isUndefined(link)) { - $scope.gist.last = link; - alertSrv.set('Gist saved', 'You will be able to access your exported dashboard file at ' + - '' + link + ' in a moment', 'success'); - } else { - alertSrv.set('Save failed', 'Gist could not be saved', 'error', 5000); - } - }); - }; - - $scope.gist_dblist = function (id) { - dashboard.gist_list(id).then( - function (files) { - if (files && files.length > 0) { - $scope.gist.files = files; - } else { - alertSrv.set('Gist Failed', 'Could not retrieve dashboard list from gist', 'error', 5000); - } - }); - }; + } else { + alertSrv.set('Dashboard Not Deleted','An error occurred deleting the dashboard','error',5000); + } + } + ); + }; + + $scope.elasticsearch_dblist = function(query) { + dashboard.elasticsearch_list(query,dashboard.current.loader.load_elasticsearch_size).then( + function(result) { + if (!_.isUndefined(result.response.docs)) { + var docs = []; + for (var i = 0; i < result.response.docs.length; i++) { + var doc ={}; + doc['id'] = result.response.docs[i].id; + doc['server'] = angular.fromJson(result.response.docs[i].dashboard).solr.server; + docs.push(doc); + } + $scope.elasticsearch.dashboards = docs; + } + }); + }; + + $scope.save_gist = function() { + dashboard.save_gist($scope.gist.title).then( + function(link) { + if(!_.isUndefined(link)) { + $scope.gist.last = link; + alertSrv.set('Gist saved','You will be able to access your exported dashboard file at '+ + ''+link+' in a moment','success'); + } else { + alertSrv.set('Save failed','Gist could not be saved','error',5000); + } + }); + }; + + $scope.gist_dblist = function(id) { + dashboard.gist_list(id).then( + function(files) { + if(files && files.length > 0) { + $scope.gist.files = files; + } else { + alertSrv.set('Gist Failed','Could not retrieve dashboard list from gist','error',5000); + } + }); + }; - function parseDashboardList(dashboardList) { - var docs = []; - for (var i=0; i < dashboardList.length; i++) { - var doc = {}; - if (config.USE_FUSION) { - doc.id = dashboardList[i].name; - // Don't need doc.server for Fusion Blob Store API. - doc.server = ''; - } else { - doc.id = dashboardList[i].id; - // Handle a case where the dashboard field is a multi-valued field (array). - if (dashboardList[i][self.DASHBOARD_FIELD] instanceof Array) { - doc.server = angular.fromJson(dashboardList[i][self.DASHBOARD_FIELD][0]).solr.server; - } else { - doc.server = angular.fromJson(dashboardList[i][self.DASHBOARD_FIELD]).solr.server; - } - } - docs.push(doc); - } + }); - return docs; - } - }); -}); +}); \ No newline at end of file diff --git a/src/app/controllers/language.js b/src/app/controllers/language.js new file mode 100644 index 000000000..4b440666b --- /dev/null +++ b/src/app/controllers/language.js @@ -0,0 +1,20 @@ +define([ + 'angular', + + 'underscore' + ], + function (angular) { + 'use strict'; + + var module = angular.module('kibana.controllers'); + + module.controller('LanguageSwitchingCtrl', ['$scope', '$translate', function (scope, $translate) { + scope.switching = function(lang){ + $translate.use(lang); + window.localStorage.lang = lang; + window.location.reload(); + }; + scope.cur_lang = $translate.use(); + }]); + + }); diff --git a/src/app/controllers/row.js b/src/app/controllers/row.js old mode 100755 new mode 100644 index ddcbb3ab2..fe947ecda --- a/src/app/controllers/row.js +++ b/src/app/controllers/row.js @@ -1,73 +1,90 @@ define([ - 'angular', - 'app', - 'underscore' + 'angular', + 'app', + 'underscore' ], function (angular, app, _) { - 'use strict'; + 'use strict'; - var module = angular.module('kibana.controllers'); + var module = angular.module('kibana.controllers'); - module.controller('RowCtrl', function ($scope, $rootScope, $timeout, ejsResource, sjsResource, querySrv) { - var _d = { - title: "Row", - height: "150px", - collapse: false, - collapsable: true, - editable: true, - panels: [] - }; + module.controller('RowCtrl', function($scope, $rootScope, $timeout, ejsResource, sjsResource, querySrv,dashboard, filterSrv) { + var _d = { + title: "Row", + height: "150px", + collapse: false, + collapsable: true, + editable: true, + panels: [], + }; - _.defaults($scope.row, _d); + _.defaults($scope.row,_d); - $scope.init = function () { - $scope.querySrv = querySrv; - $scope.reset_panel(); - }; + $scope.init = function() { + $scope.querySrv = querySrv; + $scope.reset_panel(); + }; - $scope.toggle_row = function (row) { - if (!row.collapsable) { - return; - } - row.collapse = row.collapse ? false : true; - if (!row.collapse) { - $timeout(function () { - $scope.$broadcast('render'); - }); - } - }; + $scope.toggle_row = function(row) { + if(!row.collapsable) { + return; + } + row.collapse = row.collapse ? false : true; + if (!row.collapse) { + $timeout(function() { + $scope.$broadcast('render'); + }); + } + }; - $scope.rowSpan = function (row) { - var panels = _.filter(row.panels, function (p) { - return $scope.isPanel(p); - }); - return _.reduce(_.pluck(panels, 'span'), function (p, v) { - return p + v; - }, 0); - }; + $scope.rowSpan = function(row) { + var panels = _.filter(row.panels, function(p) { + return $scope.isPanel(p); + }); + _.reduce(_.pluck(panels,'span'), function(p,v) { + return p+v; + },0); + return _.reduce(_.pluck(panels,'span'), function(p,v) { + return p+v; + },0); - // This can be overridden by individual panels - $scope.close_edit = function () { - $scope.$broadcast('render'); - }; + }; - $scope.add_panel = function (row, panel) { - $scope.row.panels.push(panel); - }; + // This can be overridden by individual panels + $scope.close_edit = function() { + $scope.$broadcast('render'); + }; + + $scope.remove = function() { + var ids = dashboard.current.filterids; + if (ids[ids.length-1] !== 0){ + filterSrv.remove(ids[ids.length-1]); + dashboard.refresh();} + }; + $scope.hide_head = function() { + dashboard.current.hide_head = !dashboard.current.hide_head; + }; - $scope.reset_panel = function (type) { - var - defaultSpan = 4, - _as = 12 - $scope.rowSpan($scope.row); + $scope.add_panel = function(row,panel) { + $scope.row.panels.push(panel); + }; - $scope.panel = { - error: false, - span: _as < defaultSpan && _as > 0 ? _as : defaultSpan, - editable: true, - type: type - }; + $scope.reset_panel = function(type) { + var + defaultSpan = 4, + _as = 12-$scope.rowSpan($scope.row); + + $scope.panel = { + error : false, + span : _as < defaultSpan && _as >= 0 ? _as : defaultSpan, + editable: true, + type : type }; + }; + + $scope.init(); + + } + ); - $scope.init(); - }); }); diff --git a/src/app/dashboards/160.json b/src/app/dashboards/160.json new file mode 100644 index 000000000..c8526f3eb --- /dev/null +++ b/src/app/dashboards/160.json @@ -0,0 +1,1962 @@ +{ + "title": "Neusoftï¼å¹³å°äº§å“实时仪表盘", + "services": { + "query": { + "idQueue": [ + 3, + 4 + ], + "list": { + "0": { + "query": "*:*", + "alias": "Risk% ", + "color": "#EA6460", + "id": 0, + "pin": false, + "type": "lucene" + }, + "1": { + "id": 1, + "color": "#E5AC0E", + "query": "*:*", + "alias": "Warning% ", + "pin": false + }, + "2": { + "id": 2, + "color": "#1F78C1", + "query": "*:*", + "alias": "Normal% ", + "pin": false + } + }, + "ids": [ + 0, + 1, + 2 + ] + }, + "filter": { + "idQueue": [ + 1, + 2, + 3 + ], + "list": { + "0": { + "from": "NOW/HOUR-24HOUR", + "to": "NOW/HOUR%2B1HOUR", + "field": "rs_timestamp", + "type": "time", + "fromDateObj": "2017-02-09T01:14:52.998Z", + "toDateObj": "2017-02-10T01:14:52.998Z", + "mandate": "must", + "active": true, + "alias": "", + "id": 0 + } + }, + "ids": [ + 0 + ] + } + }, + "rows": [ + { + "title": "Query and Time Window", + "height": "50px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "error": "", + "span": 8, + "editable": true, + "type": "timepicker", + "loadingEditor": false, + "status": "Stable", + "mode": "relative", + "time_options": [ + "6h", + "12h", + "24h", + "48h", + "72h", + "5d", + "7d", + "10d", + "15d", + "30d", + "90d", + "180d", + "1y", + "3y", + "5y" + ], + "timespan": "24h", + "timefield": "rs_timestamp", + "timeformat": "", + "refresh": { + "enable": true, + "interval": 100, + "min": 3 + }, + "filter_id": 0, + "spyable": true, + "title": "æ—¶é—´è½´" + }, + { + "span": 4, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=user_ipaddress&facet.limit=100000&facet.missing=true&f.user_ipaddress.facet.sort=count&fq=app_id:Platform System", + "custom": "&fq=app_id:Platform System" + }, + "mode": "count", + "field": "user_ipaddress", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 100000, + "sortBy": "count", + "order": "descending", + "style": { + "font-size": "48pt" + }, + "donut": false, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "horizontal", + "chart": "hits", + "counter_pos": "none", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "å¹³å°äº§å“ ï¼ åœ¨çº¿ç”¨æˆ·", + "threshold_first": 3000, + "threshold_second": 5000, + "fontsize": 20 + } + ] + }, + { + "title": "WARNING", + "height": "550px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 3, + "editable": true, + "type": "map", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&rows=0&facet=true&facet.field=ipcode&facet.limit=100000", + "custom": "&fq=app_id:Platform System" + }, + "mode": "count", + "field": "ipcode", + "stats_field": "", + "decimal_points": 0, + "map": "china", + "useNames": false, + "colors": [ + "#A0E2E2", + "#265656" + ], + "size": 100000, + "exclude": [], + "spyable": true, + "index_limit": 0, + "show_queries": true, + "title": "å¹³å°äº§å“ ï¼ ç”¨æˆ·åˆ†å¸ƒ" + }, + { + "span": 6, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=connectElapsed&facet.limit=100000&facet.missing=true&f.connectElapsed.facet.sort=count&fq=app_id:Platform System", + "custom": "&fq=app_id:Platform System" + }, + "mode": "count", + "field": "connectElapsed", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 100000, + "sortBy": "count", + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": false, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "horizontal", + "chart": "dashboard", + "counter_pos": "none", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "å¹³å°äº§å“ï¼ å¥åº·åº¦", + "threshold_first": 5000, + "threshold_second": 10000, + "fontsize": 20 + }, + { + "span": 3, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=user_ipaddress&facet.limit=100000&facet.missing=true&f.user_ipaddress.facet.sort=count&fq=app_id:Platform System", + "custom": "&fq=app_id:Platform System" + }, + "mode": "count", + "field": "user_ipaddress", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 100000, + "sortBy": "count", + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": false, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "horizontal", + "chart": "ebar", + "counter_pos": "none", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "å¹³å°äº§å“ï¼ç”¨æˆ·ç‚¹å‡»TOP5", + "threshold_first": 3000, + "threshold_second": 5000, + "fontsize": 20 + } + ] + }, + { + "title": "Change", + "height": "80px", + "editable": true, + "collapse": true, + "collapsable": true, + "panels": [ + { + "span": 4, + "editable": true, + "type": "ticker", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-02-09T01:14:52.998Z&facet.range.end=2017-02-10T01:14:52.998Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-02-09T00:14:52.998Z&facet.range.end=2017-02-10T00:14:52.998Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-02-09T01:14:52.998Z&facet.range.end=2017-02-10T01:14:52.998Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-02-09T00:14:52.998Z&facet.range.end=2017-02-10T00:14:52.998Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-02-09T01:14:52.998Z&facet.range.end=2017-02-10T01:14:52.998Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-02-09T00:14:52.998Z&facet.range.end=2017-02-10T00:14:52.998Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\n" + }, + "style": { + "font-size": "14pt" + }, + "ago": "1h", + "arrangement": "horizontal", + "spyable": true, + "show_queries": false, + "title": "SSA SYSTEM-Risk chaange(hour)" + }, + { + "span": 4, + "editable": true, + "type": "ticker", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-02-09T01:14:52.998Z&facet.range.end=2017-02-10T01:14:52.998Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-02-08T01:14:52.998Z&facet.range.end=2017-02-09T01:14:52.998Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-02-09T01:14:52.998Z&facet.range.end=2017-02-10T01:14:52.998Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-02-08T01:14:52.998Z&facet.range.end=2017-02-09T01:14:52.998Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-02-09T01:14:52.998Z&facet.range.end=2017-02-10T01:14:52.998Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-02-08T01:14:52.998Z&facet.range.end=2017-02-09T01:14:52.998Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\n" + }, + "style": { + "font-size": "14pt" + }, + "ago": "1d", + "arrangement": "horizontal", + "spyable": true, + "show_queries": true, + "title": "SSA SYSTEM-Risk chaange(day)" + }, + { + "span": 4, + "editable": true, + "type": "ticker", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-02-09T01:14:52.998Z&facet.range.end=2017-02-10T01:14:52.998Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-02-02T01:14:52.998Z&facet.range.end=2017-02-03T01:14:52.998Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-02-09T01:14:52.998Z&facet.range.end=2017-02-10T01:14:52.998Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-02-02T01:14:52.998Z&facet.range.end=2017-02-03T01:14:52.998Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-02-09T01:14:52.998Z&facet.range.end=2017-02-10T01:14:52.998Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-02-02T01:14:52.998Z&facet.range.end=2017-02-03T01:14:52.998Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\n" + }, + "style": { + "font-size": "14pt" + }, + "ago": "1w", + "arrangement": "horizontal", + "spyable": true, + "show_queries": true, + "title": "SSA SYSTEM-Risk chaange(week)" + } + ] + }, + { + "title": "EVENT COUNT", + "height": "200px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 12, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "counts", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=connectElapsed%3A%5B10000%20TO%20*%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/HOUR-24HOUR&facet.range.end=NOW/HOUR%2B1HOUR&facet.range.gap=%2B10MINUTE\nq=connectElapsed%3A%5B5000%20TO%2010000%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/HOUR-24HOUR&facet.range.end=NOW/HOUR%2B1HOUR&facet.range.gap=%2B10MINUTE\nq=connectElapsed%3A%5B0%20TO%205000%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/HOUR-24HOUR&facet.range.end=NOW/HOUR%2B1HOUR&facet.range.gap=%2B10MINUTE\n", + "custom": "&fq=app_id:Platform System" + }, + "max_rows": 100000, + "value_field": "connectElapsed", + "group_field": null, + "sum_value": false, + "auto_int": true, + "resolution": 100, + "interval": "10m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": true, + "bars": false, + "stack": true, + "points": false, + "lines": true, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": true, + "show_queries": true, + "tooltip": { + "value_type": "individual", + "query_as_alias": false + }, + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "å¹³å°äº§å“ï¼äº‹åŠ¡ç»Ÿè®¡", + "reverse": 0, + "segment": 3, + "threshold_first": 5000, + "threshold_second": 10000, + "threshold_third": 3000, + "total_first": "%" + } + ] + }, + { + "title": "response time", + "height": "200px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 6, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=responseElapsed%3A%5B5000%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp responseElapsed\nq=responseElapsed%3A%5B3000%20TO%205000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp responseElapsed\nq=responseElapsed%3A%5B0%20TO%203000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp responseElapsed\n", + "custom": "&fq=app_id:Platform System&fq=responseElapsed:[0 TO 1000000]" + }, + "max_rows": 100000, + "value_field": "responseElapsed", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "10m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "å¹³å°äº§å“ï¼å“应时间(ms)", + "reverse": 0, + "segment": 3, + "threshold_first": 3000, + "threshold_second": 5000, + "threshold_third": 3000, + "total_first": "%" + }, + { + "span": 6, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=connectElapsed%3A%5B10000%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp connectElapsed\nq=connectElapsed%3A%5B5000%20TO%2010000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp connectElapsed\nq=connectElapsed%3A%5B0%20TO%205000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp connectElapsed\n", + "custom": "&fq=app_id:Platform System&fq=connectElapsed:[0 TO 100000]" + }, + "max_rows": 100000, + "value_field": "connectElapsed", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "10m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "å¹³å°äº§å“ ï¼æœåŠ¡è¿žæŽ¥æ—¶é—´(MS)", + "reverse": 0, + "segment": 3, + "threshold_first": 5000, + "threshold_second": 10000, + "threshold_third": 3000, + "total_first": "%" + } + ] + }, + { + "title": "RESPONSE", + "height": "200px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 6, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=domElapsed%3A%5B5000%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domElapsed\nq=domElapsed%3A%5B3000%20TO%205000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domElapsed\nq=domElapsed%3A%5B0%20TO%203000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domElapsed\n", + "custom": "&fq=-domElapsed:[40000 TO *]&fq=app_id:Platform System" + }, + "max_rows": 100000, + "value_field": "domElapsed", + "group_field": null, + "auto_int": true, + "resolution": 200, + "interval": "5m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 4, + "linewidth": 3, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": false, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "å¹³å°äº§å“ï¼é¡µé¢åŠ è½½æ—¶é—´(ms)", + "reverse": 0, + "segment": 3, + "threshold_first": 3000, + "threshold_second": 5000, + "threshold_third": 3000, + "total_first": "%" + }, + { + "span": 6, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=domContentLoadedElapsed%3A%5B5000%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domContentLoadedElapsed\nq=domContentLoadedElapsed%3A%5B3000%20TO%205000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domContentLoadedElapsed\nq=domContentLoadedElapsed%3A%5B0%20TO%203000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domContentLoadedElapsed\n", + "custom": "&fq=app_id:Platform System" + }, + "max_rows": 100000, + "value_field": "domContentLoadedElapsed", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "10m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 0, + "linewidth": 3, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "å¹³å°äº§å“ï¼å†…容加载时间(ms)", + "reverse": 0, + "segment": 3, + "threshold_first": 3000, + "threshold_second": 5000, + "threshold_third": 3000, + "total_first": "%" + } + ] + }, + { + "title": "time", + "height": "200px", + "editable": true, + "collapse": true, + "collapsable": true, + "panels": [] + }, + { + "title": "Message", + "height": "190px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 4, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=cpu%3A%5B80%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp cpu\nq=cpu%3A%5B60%20TO%2080%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp cpu\nq=cpu%3A%5B0%20TO%2060%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp cpu\n", + "custom": "" + }, + "max_rows": 100000, + "reverse": 0, + "segment": 3, + "threshold_first": 60, + "threshold_second": 80, + "threshold_third": 3000, + "value_field": "cpu", + "group_field": null, + "auto_int": true, + "total_first": "%", + "resolution": 100, + "interval": "10m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": false, + "stack": true, + "points": false, + "lines": true, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "individual", + "query_as_alias": false + }, + "title": "å¹³å°äº§å“ï¼CPU 使用率(%)" + }, + { + "span": 4, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=UsedMemery%3A%5B4000%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp UsedMemery\nq=UsedMemery%3A%5B3000%20TO%204000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp UsedMemery\nq=UsedMemery%3A%5B0%20TO%203000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp UsedMemery\n", + "custom": "" + }, + "max_rows": 100000, + "value_field": "UsedMemery", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "10m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": false, + "stack": true, + "points": false, + "lines": true, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": false, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "individual", + "query_as_alias": false + }, + "title": "å¹³å°äº§å“ï¼å†…存使用率(MB)", + "reverse": 0, + "segment": 3, + "threshold_first": 3000, + "threshold_second": 4000, + "threshold_third": 3000, + "total_first": "%" + }, + { + "span": 4, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=FreeDiskSpace%3A%5B0%20TO%20100%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp FreeDiskSpace\nq=FreeDiskSpace%3A%5B100%20TO%2020%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp FreeDiskSpace\nq=FreeDiskSpace%3A%5B20%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp FreeDiskSpace\n", + "custom": "" + }, + "max_rows": 100000, + "value_field": "FreeDiskSpace", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "10m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": false, + "stack": true, + "points": false, + "lines": true, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "individual", + "query_as_alias": false + }, + "title": "å¹³å°äº§å“ï¼ç£ç›˜å‰©ä½™(GB)", + "reverse": 1, + "segment": 3, + "threshold_first": 100, + "threshold_second": 20, + "threshold_third": 3000, + "total_first": "%" + } + ] + }, + { + "title": "", + "height": "250px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 4, + "editable": true, + "type": "pies", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=dvce_type&facet.limit=100000&facet.missing=true&f.dvce_type.facet.sort=count&fq=app_id:Platform System", + "custom": "&fq=app_id:Platform System" + }, + "mode": "count", + "field": "dvce_type", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 100000, + "sortBy": "count", + "order": "descending", + "fontsize": 14, + "donut": true, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "vertical", + "RoseType": "area", + "chart": "pie", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#1a93f9", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "eLegend": true, + "title": "å¹³å°äº§å“ ï¼ç”¨æˆ·è®¾å¤‡", + "ylabels": true + }, + { + "span": 4, + "editable": true, + "type": "tagcloud", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=br_name&facet.limit=100000", + "custom": "&fq=app_id:Platform System" + }, + "field": "br_name", + "size": 100000, + "alignment": "horizontal", + "fontScale": 4, + "ignoreStopWords": false, + "spyable": true, + "show_queries": true, + "title": "å¹³å°äº§å“ï¼ ç”¨æˆ·æµè§ˆå™¨" + }, + { + "span": 4, + "editable": true, + "type": "pies", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=metric&facet.limit=10&facet.missing=true&f.metric.facet.sort=count", + "custom": "" + }, + "mode": "count", + "field": "metric", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10, + "sortBy": "count", + "order": "descending", + "fontsize": 12, + "donut": false, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "vertical", + "RoseType": "area", + "chart": "radar", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "å¹³å°äº§å“ï¼ ç”¨æˆ·æµè§ˆé¡µé¢å¯¹æ¯”", + "ylabels": true + } + ] + }, + { + "title": "PIE", + "height": "250px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 6, + "editable": true, + "type": "pies", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=os_name&facet.limit=10&facet.missing=true&f.os_name.facet.sort=count&fq=app_id:Platform System", + "custom": "&fq=app_id:Platform System" + }, + "mode": "count", + "field": "os_name", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10, + "sortBy": "count", + "order": "descending", + "fontsize": 12, + "donut": false, + "tilt": false, + "labels": true, + "ylabels": true, + "logAxis": false, + "arrangement": "vertical", + "RoseType": "area", + "chart": "bars", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "å¹³å°äº§å“ ï¼ ç”¨æˆ·æ“作系统 top 10" + }, + { + "span": 6, + "editable": true, + "type": "pies", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=application&facet.limit=100000&facet.missing=true&f.application.facet.sort=count&fq=app_id:Platform System", + "custom": "&fq=app_id:Platform System" + }, + "mode": "count", + "field": "application", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 100000, + "sortBy": "count", + "order": "descending", + "fontsize": 14, + "donut": false, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "horizontal", + "RoseType": "radius", + "chart": "rosepie", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#1a93f9", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "eLegend": false, + "title": "å¹³å°äº§å“-用户æµè§ˆäº§å“对比", + "ylabels": true + } + ] + }, + { + "title": "IP", + "height": "250px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 6, + "editable": true, + "type": "pies", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=Isp&facet.limit=10&facet.missing=true&f.Isp.facet.sort=count", + "custom": "" + }, + "mode": "count", + "field": "Isp", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10, + "sortBy": "count", + "order": "descending", + "fontsize": 12, + "donut": false, + "tilt": false, + "labels": true, + "ylabels": true, + "logAxis": false, + "arrangement": "vertical", + "RoseType": "area", + "chart": "bar", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#1a75f9", + "#1ab0f9", + "#42d3f0", + "#e59d87", + "#759aa0", + "#dc6b67", + "#efdd79", + "#8dc1aa", + "#ea7d52", + "#8dace7", + "#a6a1e1", + "#FECDA3", + "#FED980", + "#bcf924", + "#f9ac24", + "#8224f9", + "#24e5f9", + "#f96524" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "å¹³å°äº§å“ ï¼ ç”¨æˆ·æ¥æº top 10", + "eLegend": true + }, + { + "span": 6, + "editable": true, + "type": "pies", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=City&facet.limit=10000&facet.missing=true&f.City.facet.sort=count", + "custom": "" + }, + "mode": "count", + "field": "City", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10000, + "sortBy": "count", + "order": "descending", + "fontsize": 12, + "donut": false, + "tilt": false, + "labels": false, + "ylabels": true, + "logAxis": false, + "arrangement": "vertical", + "RoseType": "area", + "chart": "pie", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#1a75f9", + "#1ab0f9", + "#42d3f0", + "#e59d87", + "#759aa0", + "#dc6b67", + "#efdd79", + "#8dc1aa", + "#ea7d52", + "#8dace7", + "#a6a1e1", + "#FECDA3", + "#FED980", + "#bcf924", + "#f9ac24", + "#8224f9", + "#24e5f9", + "#f96524" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "eLegend": true, + "title": "å¹³å°äº§å“-用户城市分布" + } + ] + }, + { + "title": "111", + "height": "550px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 12, + "editable": true, + "type": "china", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=City&facet.limit=10000&facet.missing=true&f.City.facet.sort=count", + "custom": "" + }, + "mode": "count", + "field": "City", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10000, + "sortBy": "count", + "order": "descending", + "logAxis": false, + "chart": "cmap", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "å¹³å°äº§å“ - 地域分布" + } + ] + }, + { + "title": "Detail", + "height": "150px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 12, + "editable": true, + "type": "fullTextSearch", + "loadingEditor": false, + "status": "Stable", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=os_name&facet.field=useragent&facet.field=page_url&facet.field=br_name&facet.field=UsedMemery&facet.field=user_ipaddress&facet.field=dvce_type&facet.field=app_id&wt=json&rows=1500&hl=true&hl.fl=useragent", + "basic_query": "q=*%3A* OR *%3A* OR *%3A*&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=os_name&facet.field=useragent&facet.field=page_url&facet.field=br_name&facet.field=UsedMemery&facet.field=user_ipaddress&facet.field=dvce_type&facet.field=app_id", + "custom": "&fq=app_id:Platform System" + }, + "size": 5, + "pages": 300, + "offset": 0, + "group": "default", + "sort": [ + "os_family" + ], + "style": { + "font-size": "12pt" + }, + "overflow": "min-height", + "fields": [ + "os_name", + "useragent", + "page_url", + "br_name", + "UsedMemery", + "user_ipaddress", + "dvce_type", + "app_id" + ], + "highlight": [], + "sortable": false, + "header": true, + "paging": true, + "field_list": true, + "trimFactor": 200, + "normTimes": true, + "spyable": true, + "saveOption": "json", + "exportSize": 1500, + "exportAll": true, + "facet_limit": 100000, + "foundResults": true, + "show_queries": true, + "title": "å¹³å°äº§å“ï¼è¯¦ç»†ä¿¡æ¯", + "header_field": "app_id", + "body_field": "useragent", + "url_field": "page_url" + } + ] + }, + { + "title": "context time", + "height": "200px", + "editable": true, + "collapse": true, + "collapsable": true, + "panels": [ + { + "error": false, + "span": 6, + "editable": true, + "type": "filtering", + "loadingEditor": false, + "spyable": true + }, + { + "error": false, + "span": 6, + "editable": true, + "type": "query", + "loadingEditor": false, + "query": "*:*", + "pinned": true, + "history": [ + "*:*", + "responseElapsed:[0 TO 20000]", + "responseElapsed:[20000 TO 30000]", + "responseElapsed:[30000 TO *]", + "responseElapsed:[20000 TO 19999]", + "responseElapsed:[0 TO 15000]", + "responseElapsed:[15000 TO 19999]", + "responseElapsed:[20000 TO *]" + ], + "spyable": true, + "remember": 10 + } + ] + } + ], + "editable": true, + "index": { + "interval": "none", + "pattern": "[logstash-]YYYY.MM.DD", + "default": "_all" + }, + "style": "dark", + "failover": false, + "panel_hints": true, + "loader": { + "save_gist": false, + "save_elasticsearch": true, + "save_local": true, + "save_default": true, + "save_temp": true, + "save_temp_ttl_enable": true, + "save_temp_ttl": "30d", + "load_gist": true, + "load_elasticsearch": true, + "load_elasticsearch_size": 20, + "load_local": true, + "hide": false, + "dropdown_collections": false, + "save_as_public": false + }, + "solr": { + "server": "http://101.201.82.138:9983/solr/", + "core_name": "apm3", + "core_list": [ + "PHP_logs", + "apm", + "apm2", + "apm3" + ], + "global_params": "" + }, + "username": "guest" +} \ No newline at end of file diff --git a/src/app/dashboards/BMW-China.json b/src/app/dashboards/BMW-China.json new file mode 100644 index 000000000..0ea2bc69b --- /dev/null +++ b/src/app/dashboards/BMW-China.json @@ -0,0 +1,1554 @@ +{ + "title": "BMW Chinaï¼Application Monitoring Dashboard", + "services": { + "query": { + "idQueue": [ + 3, + 4 + ], + "list": { + "0": { + "query": "*:*", + "alias": "Risk", + "color": "#EA6460", + "id": 0, + "pin": false, + "type": "lucene" + }, + "1": { + "id": 1, + "color": "#E5AC0E", + "query": "*:*", + "alias": "Warning", + "pin": false + }, + "2": { + "id": 2, + "color": "#508642", + "query": "*:*", + "alias": "Normal", + "pin": false + } + }, + "ids": [ + 0, + 1, + 2 + ] + }, + "filter": { + "idQueue": [ + 1, + 2, + 3 + ], + "list": { + "0": { + "from": "NOW/HOUR-12HOUR", + "to": "NOW/HOUR%2B1HOUR", + "field": "rs_timestamp", + "type": "time", + "fromDateObj": "2017-01-04T18:04:05.702Z", + "toDateObj": "2017-01-05T06:04:05.702Z", + "mandate": "must", + "active": true, + "alias": "", + "id": 0 + } + }, + "ids": [ + 0 + ] + } + }, + "rows": [ + { + "title": "Query and Time Window", + "height": "50px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "error": "", + "span": 8, + "editable": true, + "type": "timepicker", + "loadingEditor": false, + "status": "Stable", + "mode": "relative", + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "7d", + "30d", + "90d", + "1y", + "5y" + ], + "timespan": "12h", + "timefield": "rs_timestamp", + "timeformat": "", + "refresh": { + "enable": true, + "interval": 100, + "min": 3 + }, + "filter_id": 0, + "spyable": true, + "title": "time frame" + }, + { + "span": 4, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=user_ipaddress&facet.limit=100000&facet.missing=true&f.user_ipaddress.facet.sort=count&fq=app_id:BMW SSA", + "custom": "&fq=app_id:BMW SSA" + }, + "mode": "count", + "field": "user_ipaddress", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 100000, + "sortBy": "count", + "order": "descending", + "style": { + "font-size": "48pt" + }, + "donut": false, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "horizontal", + "chart": "hits", + "counter_pos": "none", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "SSA ï¼ online USERS", + "threshold_first": 3000, + "threshold_second": 5000 + } + ] + }, + { + "title": "WARNING", + "height": "550px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 3, + "editable": true, + "type": "map", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&rows=0&facet=true&facet.field=ipcode&facet.limit=100", + "custom": "&fq=app_id:BMW SSA" + }, + "mode": "count", + "field": "ipcode", + "stats_field": "", + "decimal_points": 0, + "map": "china", + "useNames": false, + "colors": [ + "#A0E2E2", + "#265656" + ], + "size": 100, + "exclude": [], + "spyable": true, + "index_limit": 0, + "show_queries": true, + "title": "SSA ï¼ user visit distribution" + }, + { + "span": 6, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=responseElapsed&facet.limit=100000&facet.missing=true&f.responseElapsed.facet.sort=count&fq=app_id:BMW SSA", + "custom": "&fq=app_id:BMW SSA" + }, + "mode": "count", + "field": "responseElapsed", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 100000, + "sortBy": "count", + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": false, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "horizontal", + "chart": "dashboard", + "counter_pos": "none", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "SSA ï¼ Health", + "threshold_first": 20000, + "threshold_second": 30000 + }, + { + "span": 3, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=user_ipaddress&facet.limit=100000&facet.missing=true&f.user_ipaddress.facet.sort=count&fq=app_id:BMW SSA", + "custom": "&fq=app_id:BMW SSA" + }, + "mode": "count", + "field": "user_ipaddress", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 100000, + "sortBy": "count", + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": false, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "horizontal", + "chart": "ebar", + "counter_pos": "none", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "SSA ï¼USER IP top5", + "threshold_first": 3000, + "threshold_second": 5000 + } + ] + }, + { + "title": "Change", + "height": "80px", + "editable": true, + "collapse": true, + "collapsable": true, + "panels": [ + { + "span": 4, + "editable": true, + "type": "ticker", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-01-04T18:04:05.702Z&facet.range.end=2017-01-05T06:04:05.702Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-01-04T17:04:05.702Z&facet.range.end=2017-01-05T05:04:05.702Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-01-04T18:04:05.702Z&facet.range.end=2017-01-05T06:04:05.702Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-01-04T17:04:05.702Z&facet.range.end=2017-01-05T05:04:05.702Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-01-04T18:04:05.702Z&facet.range.end=2017-01-05T06:04:05.702Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-01-04T17:04:05.702Z&facet.range.end=2017-01-05T05:04:05.702Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\n" + }, + "style": { + "font-size": "14pt" + }, + "ago": "1h", + "arrangement": "horizontal", + "spyable": true, + "show_queries": false, + "title": "SSA SYSTEM-Risk chaange(hour)" + }, + { + "span": 4, + "editable": true, + "type": "ticker", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-01-04T18:04:05.702Z&facet.range.end=2017-01-05T06:04:05.702Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-01-03T18:04:05.702Z&facet.range.end=2017-01-04T06:04:05.702Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-01-04T18:04:05.702Z&facet.range.end=2017-01-05T06:04:05.702Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-01-03T18:04:05.702Z&facet.range.end=2017-01-04T06:04:05.702Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-01-04T18:04:05.702Z&facet.range.end=2017-01-05T06:04:05.702Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-01-03T18:04:05.702Z&facet.range.end=2017-01-04T06:04:05.702Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\n" + }, + "style": { + "font-size": "14pt" + }, + "ago": "1d", + "arrangement": "horizontal", + "spyable": true, + "show_queries": true, + "title": "SSA SYSTEM-Risk chaange(day)" + }, + { + "span": 4, + "editable": true, + "type": "ticker", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-01-04T18:04:05.702Z&facet.range.end=2017-01-05T06:04:05.702Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-28T18:04:05.702Z&facet.range.end=2016-12-29T06:04:05.702Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-01-04T18:04:05.702Z&facet.range.end=2017-01-05T06:04:05.702Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-28T18:04:05.702Z&facet.range.end=2016-12-29T06:04:05.702Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-01-04T18:04:05.702Z&facet.range.end=2017-01-05T06:04:05.702Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-28T18:04:05.702Z&facet.range.end=2016-12-29T06:04:05.702Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\n" + }, + "style": { + "font-size": "14pt" + }, + "ago": "1w", + "arrangement": "horizontal", + "spyable": true, + "show_queries": true, + "title": "SSA SYSTEM-Risk chaange(week)" + } + ] + }, + { + "title": "EVENT COUNT", + "height": "200px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 12, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "counts", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=responseElapsed%3A%5B30000%20TO%20*%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/HOUR-12HOUR&facet.range.end=NOW/HOUR%2B1HOUR&facet.range.gap=%2B5MINUTE\nq=responseElapsed%3A%5B20000%20TO%2030000%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/HOUR-12HOUR&facet.range.end=NOW/HOUR%2B1HOUR&facet.range.gap=%2B5MINUTE\nq=responseElapsed%3A%5B0%20TO%2020000%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/HOUR-12HOUR&facet.range.end=NOW/HOUR%2B1HOUR&facet.range.gap=%2B5MINUTE\n", + "custom": "&fq=app_id:BMW SSA" + }, + "max_rows": 100000, + "value_field": "responseElapsed", + "group_field": null, + "sum_value": false, + "auto_int": true, + "resolution": 100, + "interval": "5m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": true, + "bars": false, + "stack": true, + "points": false, + "lines": true, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": true, + "show_queries": true, + "tooltip": { + "value_type": "individual", + "query_as_alias": false + }, + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "SSAï¼user experience count", + "reverse": 0, + "segment": 3, + "threshold_first": 20000, + "threshold_second": 30000, + "threshold_third": 3000 + } + ] + }, + { + "title": "response time", + "height": "200px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 6, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=responseElapsed%3A%5B30000%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp responseElapsed\nq=responseElapsed%3A%5B20000%20TO%2030000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp responseElapsed\nq=responseElapsed%3A%5B0%20TO%2020000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp responseElapsed\n", + "custom": "&fq=-responseElapsed:[60000 TO *]&fq=app_id:BMW SSA" + }, + "max_rows": 100000, + "value_field": "responseElapsed", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "5m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "SSAï¼response time(ms)", + "segment": 3, + "threshold_first": 20000, + "threshold_second": 30000, + "reverse": 0, + "threshold_third": 3000 + }, + { + "span": 6, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=connectElapsed%3A%5B30000%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp connectElapsed\nq=connectElapsed%3A%5B20000%20TO%2030000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp connectElapsed\nq=connectElapsed%3A%5B0%20TO%2020000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp connectElapsed\n", + "custom": "&fq=-connectElapsed:[40000 TO *]&fq=app_id:BMW SSA" + }, + "max_rows": 100000, + "value_field": "connectElapsed", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "5m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "SSA ï¼Server connection time(MS)", + "segment": 3, + "threshold_first": 20000, + "threshold_second": 30000, + "reverse": 0, + "threshold_third": 3000 + } + ] + }, + { + "title": "RESPONSE", + "height": "200px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 6, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=domElapsed%3A%5B30000%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domElapsed\nq=domElapsed%3A%5B20000%20TO%2030000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domElapsed\nq=domElapsed%3A%5B0%20TO%2020000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domElapsed\n", + "custom": "&fq=-domElapsed:[60000 TO *]&fq=app_id:BMW SSA" + }, + "max_rows": 100000, + "value_field": "domElapsed", + "group_field": null, + "auto_int": true, + "resolution": 200, + "interval": "5m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 4, + "linewidth": 3, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": false, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "SSAï¼page load TIME(ms)", + "segment": 3, + "threshold_first": 20000, + "threshold_second": 30000, + "reverse": 0, + "threshold_third": 3000 + }, + { + "span": 6, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=domContentLoadedElapsed%3A%5B30000%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domContentLoadedElapsed\nq=domContentLoadedElapsed%3A%5B20000%20TO%2030000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domContentLoadedElapsed\nq=domContentLoadedElapsed%3A%5B0%20TO%2020000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domContentLoadedElapsed\n", + "custom": "&fq=app_id:BMW SSA" + }, + "max_rows": 100000, + "value_field": "domContentLoadedElapsed", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "5m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 0, + "linewidth": 3, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "SSAï¼content load TIME(ms)", + "segment": 3, + "threshold_first": 20000, + "threshold_second": 30000, + "reverse": 0, + "threshold_third": 3000 + } + ] + }, + { + "title": "time", + "height": "200px", + "editable": true, + "collapse": true, + "collapsable": true, + "panels": [] + }, + { + "title": "Message", + "height": "190px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 4, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=cpu%3A%5B70%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp cpu\nq=cpu%3A%5B50%20TO%2070%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp cpu\nq=cpu%3A%5B0%20TO%2050%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp cpu\n", + "custom": "" + }, + "max_rows": 100000, + "value_field": "cpu", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "5m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": false, + "stack": true, + "points": false, + "lines": true, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "SSAï¼CPU usage(%)", + "segment": 3, + "threshold_first": 50, + "threshold_second": 70, + "reverse": 0, + "threshold_third": 3000 + }, + { + "span": 4, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=UsedMemery%3A%5B2000%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp UsedMemery\nq=UsedMemery%3A%5B1500%20TO%202000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp UsedMemery\nq=UsedMemery%3A%5B0%20TO%201500%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp UsedMemery\n", + "custom": "" + }, + "max_rows": 100000, + "value_field": "UsedMemery", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "5m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": false, + "stack": true, + "points": false, + "lines": true, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": false, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "SSAï¼memory usage(MB)", + "segment": 3, + "threshold_first": 1500, + "threshold_second": 2000, + "reverse": 0, + "threshold_third": 3000 + }, + { + "span": 4, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=FreeDiskSpace%3A%5B0%20TO%205%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp FreeDiskSpace\nq=FreeDiskSpace%3A%5B5%20TO%2020%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp FreeDiskSpace\nq=FreeDiskSpace%3A%5B20%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp FreeDiskSpace\n", + "custom": "" + }, + "max_rows": 100000, + "value_field": "FreeDiskSpace", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "5m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": false, + "stack": true, + "points": false, + "lines": true, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "SSAï¼Free disk(GB)", + "segment": 3, + "threshold_first": 5, + "threshold_second": 20, + "reverse": 1, + "threshold_third": 3000 + } + ] + }, + { + "title": "PIE", + "height": "250px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 3, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "counts", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=responseElapsed%3A%5B2000000%20TO%20*%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/HOUR-12HOUR&facet.range.end=NOW/HOUR%2B1HOUR&facet.range.gap=%2B30MINUTE\nq=responseElapsed%3A%5B1500000%20TO%202000000%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/HOUR-12HOUR&facet.range.end=NOW/HOUR%2B1HOUR&facet.range.gap=%2B30MINUTE\nq=responseElapsed%3A%5B0%20TO%201500000%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/HOUR-12HOUR&facet.range.end=NOW/HOUR%2B1HOUR&facet.range.gap=%2B30MINUTE\n", + "custom": "&fq=app_id:BMW SSA" + }, + "max_rows": 100000, + "value_field": "responseElapsed", + "group_field": null, + "auto_int": false, + "resolution": 100, + "interval": "30m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 3, + "timezone": "browser", + "spyable": false, + "zoomlinks": false, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": false, + "x-axis": false, + "y-axis": true, + "percentage": false, + "interactive": false, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "SSA ï¼ user request", + "reverse": 0, + "segment": 3, + "threshold_first": 1500000, + "threshold_second": 2000000, + "threshold_third": 3000 + }, + { + "span": 3, + "editable": true, + "type": "pies", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=os_name&facet.limit=10&facet.missing=true&f.os_name.facet.sort=count", + "custom": "" + }, + "mode": "count", + "field": "os_name", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10, + "sortBy": "count", + "order": "descending", + "fontsize": 12, + "donut": false, + "tilt": false, + "labels": false, + "logAxis": false, + "arrangement": "vertical", + "RoseType": "area", + "chart": "pie", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "eLegend": true, + "title": "SSA ï¼User OS" + }, + { + "span": 3, + "editable": true, + "type": "pies", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=dvce_type&facet.limit=10&facet.missing=true&f.dvce_type.facet.sort=count", + "custom": "" + }, + "mode": "count", + "field": "dvce_type", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10, + "sortBy": "count", + "order": "descending", + "fontsize": 14, + "donut": true, + "tilt": false, + "labels": false, + "logAxis": false, + "arrangement": "vertical", + "RoseType": "area", + "chart": "pie", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "SSA ï¼User device", + "eLegend": true + }, + { + "span": 3, + "editable": true, + "type": "tagcloud", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=br_name&facet.limit=100000", + "custom": "&fq=app_id:BMW SSA" + }, + "field": "br_name", + "size": 100000, + "alignment": "horizontal", + "fontScale": 4, + "ignoreStopWords": false, + "spyable": true, + "show_queries": true, + "title": "SSA ï¼ user browser" + } + ] + }, + { + "title": "Detail", + "height": "150px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 12, + "editable": true, + "type": "fullTextSearch", + "loadingEditor": false, + "status": "Stable", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=os_name&facet.field=useragent&facet.field=page_url&facet.field=br_name&facet.field=UsedMemery&facet.field=user_ipaddress&facet.field=dvce_type&facet.field=app_id&wt=json&rows=1500&hl=true&hl.fl=useragent", + "basic_query": "q=*%3A* OR *%3A* OR *%3A*&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=os_name&facet.field=useragent&facet.field=page_url&facet.field=br_name&facet.field=UsedMemery&facet.field=user_ipaddress&facet.field=dvce_type&facet.field=app_id", + "custom": "&fq=app_id:BMW SSA&fq=-app_id:SSA" + }, + "size": 5, + "pages": 300, + "offset": 0, + "group": "default", + "sort": [ + "os_family" + ], + "style": { + "font-size": "12pt" + }, + "overflow": "min-height", + "fields": [ + "os_name", + "useragent", + "page_url", + "br_name", + "UsedMemery", + "user_ipaddress", + "dvce_type", + "app_id" + ], + "highlight": [], + "sortable": false, + "header": true, + "paging": true, + "field_list": true, + "trimFactor": 200, + "normTimes": true, + "spyable": true, + "saveOption": "json", + "exportSize": 1500, + "exportAll": true, + "facet_limit": 100000, + "foundResults": true, + "show_queries": true, + "title": "SSA ï¼Event detail", + "header_field": "app_id", + "body_field": "useragent", + "url_field": "page_url" + } + ] + }, + { + "title": "context time", + "height": "200px", + "editable": true, + "collapse": true, + "collapsable": true, + "panels": [ + { + "error": false, + "span": 6, + "editable": true, + "type": "filtering", + "loadingEditor": false, + "spyable": true + }, + { + "error": false, + "span": 6, + "editable": true, + "type": "query", + "loadingEditor": false, + "query": "*:*", + "pinned": true, + "history": [ + "*:*", + "responseElapsed:[0 TO 20000]", + "responseElapsed:[20000 TO 30000]", + "responseElapsed:[30000 TO *]", + "responseElapsed:[20000 TO 19999]", + "responseElapsed:[0 TO 15000]", + "responseElapsed:[15000 TO 19999]", + "responseElapsed:[20000 TO *]" + ], + "spyable": true, + "remember": 10 + } + ] + } + ], + "editable": true, + "index": { + "interval": "none", + "pattern": "[logstash-]YYYY.MM.DD", + "default": "_all" + }, + "style": "dark", + "failover": false, + "panel_hints": true, + "loader": { + "save_gist": false, + "save_elasticsearch": true, + "save_local": true, + "save_default": true, + "save_temp": true, + "save_temp_ttl_enable": true, + "save_temp_ttl": "30d", + "load_gist": true, + "load_elasticsearch": true, + "load_elasticsearch_size": 20, + "load_local": true, + "hide": false, + "dropdown_collections": false, + "save_as_public": false + }, + "solr": { + "server": "/solr/", + "core_name": "apm2", + "core_list": [ + "PHP_logs", + "apm", + "apm2", + "apm3" + ], + "global_params": "" + }, + "username": "guest" +} \ No newline at end of file diff --git a/src/app/dashboards/BMW.json b/src/app/dashboards/BMW.json new file mode 100644 index 000000000..9bd080b51 --- /dev/null +++ b/src/app/dashboards/BMW.json @@ -0,0 +1,1545 @@ +{ + "title": "BMW Chinaï¼Application Monitoring Dashboard", + "services": { + "query": { + "idQueue": [ + 3, + 4 + ], + "list": { + "0": { + "query": "*:*", + "alias": "Risk", + "color": "#EA6460", + "id": 0, + "pin": false, + "type": "lucene" + }, + "1": { + "id": 1, + "color": "#E5AC0E", + "query": "*:*", + "alias": "Warning", + "pin": false + }, + "2": { + "id": 2, + "color": "#508642", + "query": "*:*", + "alias": "Normal", + "pin": false + } + }, + "ids": [ + 0, + 1, + 2 + ] + }, + "filter": { + "idQueue": [ + 1, + 2, + 3 + ], + "list": { + "0": { + "from": "NOW/DAY-7DAY", + "to": "NOW/DAY%2B1DAY", + "field": "rs_timestamp", + "type": "time", + "fromDateObj": "2016-12-29T02:25:49.101Z", + "toDateObj": "2017-01-05T02:25:49.101Z", + "mandate": "must", + "active": true, + "alias": "", + "id": 0 + } + }, + "ids": [ + 0 + ] + } + }, + "rows": [ + { + "title": "Query and Time Window", + "height": "50px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "error": "", + "span": 8, + "editable": true, + "type": "timepicker", + "loadingEditor": false, + "status": "Stable", + "mode": "relative", + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "7d", + "30d", + "90d", + "1y", + "5y" + ], + "timespan": "7d", + "timefield": "rs_timestamp", + "timeformat": "", + "refresh": { + "enable": true, + "interval": 100, + "min": 3 + }, + "filter_id": 0, + "spyable": true, + "title": "time frame" + }, + { + "span": 4, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&facet=true&facet.field=user_ipaddress&facet.limit=100000&facet.missing=true&f.user_ipaddress.facet.sort=count&fq=app_id:BMW SSA", + "custom": "&fq=app_id:BMW SSA" + }, + "mode": "count", + "field": "user_ipaddress", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 100000, + "sortBy": "count", + "order": "descending", + "style": { + "font-size": "48pt" + }, + "donut": false, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "horizontal", + "chart": "hits", + "counter_pos": "none", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "SSA ï¼ online USERS", + "threshold_first": 3000, + "threshold_second": 5000 + } + ] + }, + { + "title": "WARNING", + "height": "550px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 3, + "editable": true, + "type": "map", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&rows=0&facet=true&facet.field=ipcode&facet.limit=100", + "custom": "&fq=app_id:BMW SSA" + }, + "mode": "count", + "field": "ipcode", + "stats_field": "", + "decimal_points": 0, + "map": "china", + "useNames": false, + "colors": [ + "#A0E2E2", + "#265656" + ], + "size": 100, + "exclude": [], + "spyable": true, + "index_limit": 0, + "show_queries": true, + "title": "SSA ï¼ user visit distribution" + }, + { + "span": 6, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&facet=true&facet.field=responseElapsed&facet.limit=100000&facet.missing=true&f.responseElapsed.facet.sort=count&fq=app_id:BMW SSA", + "custom": "&fq=app_id:BMW SSA" + }, + "mode": "count", + "field": "responseElapsed", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 100000, + "sortBy": "count", + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": false, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "horizontal", + "chart": "dashboard", + "counter_pos": "none", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "SSA ï¼ Health", + "threshold_first": 20000, + "threshold_second": 30000 + }, + { + "span": 3, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&facet=true&facet.field=user_ipaddress&facet.limit=100000&facet.missing=true&f.user_ipaddress.facet.sort=count&fq=app_id:BMW SSA", + "custom": "&fq=app_id:BMW SSA" + }, + "mode": "count", + "field": "user_ipaddress", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 100000, + "sortBy": "count", + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": false, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "horizontal", + "chart": "ebar", + "counter_pos": "none", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "SSA ï¼USER IP top5", + "threshold_first": 3000, + "threshold_second": 5000 + } + ] + }, + { + "title": "Change", + "height": "80px", + "editable": true, + "collapse": true, + "collapsable": true, + "panels": [ + { + "span": 4, + "editable": true, + "type": "ticker", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-29T02:25:49.101Z&facet.range.end=2017-01-05T02:25:49.101Z&facet.range.gap=%2B8DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-29T01:25:49.101Z&facet.range.end=2017-01-05T01:25:49.101Z&facet.range.gap=%2B8DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-29T02:25:49.101Z&facet.range.end=2017-01-05T02:25:49.101Z&facet.range.gap=%2B8DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-29T01:25:49.101Z&facet.range.end=2017-01-05T01:25:49.101Z&facet.range.gap=%2B8DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-29T02:25:49.101Z&facet.range.end=2017-01-05T02:25:49.101Z&facet.range.gap=%2B8DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-29T01:25:49.101Z&facet.range.end=2017-01-05T01:25:49.101Z&facet.range.gap=%2B8DAY&facet.range.hardend=true&facet.range.other=between\n-----------\n" + }, + "style": { + "font-size": "14pt" + }, + "ago": "1h", + "arrangement": "horizontal", + "spyable": true, + "show_queries": false, + "title": "SSA SYSTEM-Risk chaange(hour)" + }, + { + "span": 4, + "editable": true, + "type": "ticker", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-29T02:25:49.101Z&facet.range.end=2017-01-05T02:25:49.101Z&facet.range.gap=%2B8DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-28T02:25:49.101Z&facet.range.end=2017-01-04T02:25:49.101Z&facet.range.gap=%2B8DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-29T02:25:49.101Z&facet.range.end=2017-01-05T02:25:49.101Z&facet.range.gap=%2B8DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-28T02:25:49.101Z&facet.range.end=2017-01-04T02:25:49.101Z&facet.range.gap=%2B8DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-29T02:25:49.101Z&facet.range.end=2017-01-05T02:25:49.101Z&facet.range.gap=%2B8DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-28T02:25:49.101Z&facet.range.end=2017-01-04T02:25:49.101Z&facet.range.gap=%2B8DAY&facet.range.hardend=true&facet.range.other=between\n-----------\n" + }, + "style": { + "font-size": "14pt" + }, + "ago": "1d", + "arrangement": "horizontal", + "spyable": true, + "show_queries": true, + "title": "SSA SYSTEM-Risk chaange(day)" + }, + { + "span": 4, + "editable": true, + "type": "ticker", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-29T02:25:49.101Z&facet.range.end=2017-01-05T02:25:49.101Z&facet.range.gap=%2B8DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-22T02:25:49.101Z&facet.range.end=2016-12-29T02:25:49.101Z&facet.range.gap=%2B8DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-29T02:25:49.101Z&facet.range.end=2017-01-05T02:25:49.101Z&facet.range.gap=%2B8DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-22T02:25:49.101Z&facet.range.end=2016-12-29T02:25:49.101Z&facet.range.gap=%2B8DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-29T02:25:49.101Z&facet.range.end=2017-01-05T02:25:49.101Z&facet.range.gap=%2B8DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-22T02:25:49.101Z&facet.range.end=2016-12-29T02:25:49.101Z&facet.range.gap=%2B8DAY&facet.range.hardend=true&facet.range.other=between\n-----------\n" + }, + "style": { + "font-size": "14pt" + }, + "ago": "1w", + "arrangement": "horizontal", + "spyable": true, + "show_queries": true, + "title": "SSA SYSTEM-Risk chaange(week)" + } + ] + }, + { + "title": "EVENT COUNT", + "height": "200px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 12, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "counts", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=responseElapsed%3A%5B30000%20TO%20*%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/DAY-7DAY&facet.range.end=NOW/DAY%2B1DAY&facet.range.gap=%2B1HOUR\nq=responseElapsed%3A%5B20000%20TO%2030000%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/DAY-7DAY&facet.range.end=NOW/DAY%2B1DAY&facet.range.gap=%2B1HOUR\nq=responseElapsed%3A%5B0%20TO%2020000%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/DAY-7DAY&facet.range.end=NOW/DAY%2B1DAY&facet.range.gap=%2B1HOUR\n", + "custom": "&fq=app_id:BMW SSA" + }, + "max_rows": 100000, + "value_field": "responseElapsed", + "group_field": null, + "sum_value": false, + "auto_int": true, + "resolution": 100, + "interval": "1h", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": true, + "bars": false, + "stack": true, + "points": false, + "lines": true, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": true, + "show_queries": true, + "tooltip": { + "value_type": "individual", + "query_as_alias": false + }, + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "SSAï¼user experience count", + "reverse": 0, + "segment": 3, + "threshold_first": 20000, + "threshold_second": 30000, + "threshold_third": 3000 + } + ] + }, + { + "title": "response time", + "height": "200px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 6, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=responseElapsed%3A%5B30000%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&fl=rs_timestamp responseElapsed\nq=responseElapsed%3A%5B20000%20TO%2030000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&fl=rs_timestamp responseElapsed\nq=responseElapsed%3A%5B0%20TO%2020000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&fl=rs_timestamp responseElapsed\n", + "custom": "&fq=-responseElapsed:[60000 TO *]&fq=app_id:BMW SSA" + }, + "max_rows": 100000, + "value_field": "responseElapsed", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "1h", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "SSAï¼response time(ms)", + "segment": 3, + "threshold_first": 20000, + "threshold_second": 30000, + "reverse": 0, + "threshold_third": 3000 + }, + { + "span": 6, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=connectElapsed%3A%5B30000%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&fl=rs_timestamp connectElapsed\nq=connectElapsed%3A%5B20000%20TO%2030000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&fl=rs_timestamp connectElapsed\nq=connectElapsed%3A%5B0%20TO%2020000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&fl=rs_timestamp connectElapsed\n", + "custom": "&fq=-connectElapsed:[40000 TO *]&fq=app_id:BMW SSA" + }, + "max_rows": 100000, + "value_field": "connectElapsed", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "1h", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "SSA ï¼Server connection time(MS)", + "segment": 3, + "threshold_first": 20000, + "threshold_second": 30000, + "reverse": 0, + "threshold_third": 3000 + } + ] + }, + { + "title": "RESPONSE", + "height": "200px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 6, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=domElapsed%3A%5B30000%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&fl=rs_timestamp domElapsed\nq=domElapsed%3A%5B20000%20TO%2030000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&fl=rs_timestamp domElapsed\nq=domElapsed%3A%5B0%20TO%2020000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&fl=rs_timestamp domElapsed\n", + "custom": "&fq=-domElapsed:[60000 TO *]&fq=app_id:BMW SSA" + }, + "max_rows": 100000, + "value_field": "domElapsed", + "group_field": null, + "auto_int": true, + "resolution": 200, + "interval": "1h", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 4, + "linewidth": 3, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": false, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "SSAï¼page load TIME(ms)", + "segment": 3, + "threshold_first": 20000, + "threshold_second": 30000, + "reverse": 0, + "threshold_third": 3000 + }, + { + "span": 6, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=domContentLoadedElapsed%3A%5B30000%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&fl=rs_timestamp domContentLoadedElapsed\nq=domContentLoadedElapsed%3A%5B20000%20TO%2030000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&fl=rs_timestamp domContentLoadedElapsed\nq=domContentLoadedElapsed%3A%5B0%20TO%2020000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&fl=rs_timestamp domContentLoadedElapsed\n", + "custom": "&fq=app_id:BMW SSA" + }, + "max_rows": 100000, + "value_field": "domContentLoadedElapsed", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "1h", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 0, + "linewidth": 3, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "SSAï¼content load TIME(ms)", + "segment": 3, + "threshold_first": 20000, + "threshold_second": 30000, + "reverse": 0, + "threshold_third": 3000 + } + ] + }, + { + "title": "time", + "height": "200px", + "editable": true, + "collapse": true, + "collapsable": true, + "panels": [] + }, + { + "title": "Message", + "height": "190px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 4, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=cpu%3A%5B70%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&fl=rs_timestamp cpu\nq=cpu%3A%5B50%20TO%2070%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&fl=rs_timestamp cpu\nq=cpu%3A%5B0%20TO%2050%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&fl=rs_timestamp cpu\n", + "custom": "" + }, + "max_rows": 100000, + "value_field": "cpu", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "1h", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": false, + "stack": true, + "points": false, + "lines": true, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "SSAï¼CPU usage(%)", + "segment": 3, + "threshold_first": 50, + "threshold_second": 70, + "reverse": 0, + "threshold_third": 3000 + }, + { + "span": 4, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=UsedMemery%3A%5B2000%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&fl=rs_timestamp UsedMemery\nq=UsedMemery%3A%5B1500%20TO%202000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&fl=rs_timestamp UsedMemery\nq=UsedMemery%3A%5B0%20TO%201500%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&fl=rs_timestamp UsedMemery\n", + "custom": "" + }, + "max_rows": 100000, + "value_field": "UsedMemery", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "1h", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": false, + "stack": true, + "points": false, + "lines": true, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": false, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "SSAï¼memory usage(MB)", + "segment": 3, + "threshold_first": 1500, + "threshold_second": 2000, + "reverse": 0, + "threshold_third": 3000 + }, + { + "span": 4, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=FreeDiskSpace%3A%5B0%20TO%205%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&fl=rs_timestamp FreeDiskSpace\nq=FreeDiskSpace%3A%5B5%20TO%2020%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&fl=rs_timestamp FreeDiskSpace\nq=FreeDiskSpace%3A%5B20%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&fl=rs_timestamp FreeDiskSpace\n", + "custom": "" + }, + "max_rows": 100000, + "value_field": "FreeDiskSpace", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "1h", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": false, + "stack": true, + "points": false, + "lines": true, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "SSAï¼Free disk(GB)", + "segment": 3, + "threshold_first": 5, + "threshold_second": 20, + "reverse": 1, + "threshold_third": 3000 + } + ] + }, + { + "title": "PIE", + "height": "250px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 3, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "counts", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=responseElapsed%3A%5B2000000%20TO%20*%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/DAY-7DAY&facet.range.end=NOW/DAY%2B1DAY&facet.range.gap=%2B30MINUTE\nq=responseElapsed%3A%5B1500000%20TO%202000000%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/DAY-7DAY&facet.range.end=NOW/DAY%2B1DAY&facet.range.gap=%2B30MINUTE\nq=responseElapsed%3A%5B0%20TO%201500000%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/DAY-7DAY&facet.range.end=NOW/DAY%2B1DAY&facet.range.gap=%2B30MINUTE\n", + "custom": "&fq=app_id:BMW SSA" + }, + "max_rows": 100000, + "value_field": "responseElapsed", + "group_field": null, + "auto_int": false, + "resolution": 100, + "interval": "30m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 3, + "timezone": "browser", + "spyable": false, + "zoomlinks": false, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": false, + "x-axis": false, + "y-axis": true, + "percentage": false, + "interactive": false, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "SSA ï¼ user request", + "reverse": 0, + "segment": 3, + "threshold_first": 1500000, + "threshold_second": 2000000, + "threshold_third": 3000 + }, + { + "span": 3, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&facet=true&facet.field=os_name&facet.limit=100000&facet.missing=true&f.os_name.facet.sort=count&fq=app_id:BMW SSA", + "custom": "&fq=app_id:BMW SSA" + }, + "mode": "count", + "field": "os_name", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 100000, + "sortBy": "count", + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": false, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "vertical", + "chart": "pie", + "counter_pos": "left", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#104E8B", + "#65C5DB", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "SSA ï¼ USER os", + "threshold_first": 3000, + "threshold_second": 5000 + }, + { + "span": 3, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&facet=true&facet.field=dvce_type&facet.limit=100000&facet.missing=true&f.dvce_type.facet.sort=index&fq=app_id:BMW SSA&fq=-dvce_type:Unknown", + "custom": "&fq=app_id:BMW SSA&fq=-dvce_type:Unknown" + }, + "mode": "count", + "field": "dvce_type", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 100000, + "sortBy": "index", + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": true, + "tilt": false, + "labels": false, + "logAxis": false, + "arrangement": "vertical", + "chart": "pie", + "counter_pos": "left", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#104E8B", + "#65C5DB", + "#C15C17", + "#890F02", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "SSA ï¼User device", + "threshold_first": 3000, + "threshold_second": 5000 + }, + { + "span": 3, + "editable": true, + "type": "tagcloud", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&rows=0&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&facet=true&facet.field=br_name&facet.limit=100000", + "custom": "&fq=app_id:BMW SSA" + }, + "field": "br_name", + "size": 100000, + "alignment": "horizontal", + "fontScale": 4, + "ignoreStopWords": false, + "spyable": true, + "show_queries": true, + "title": "SSA ï¼ user browser" + } + ] + }, + { + "title": "Detail", + "height": "150px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 12, + "editable": true, + "type": "fullTextSearch", + "loadingEditor": false, + "status": "Stable", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&facet=true&facet.field=os_name&facet.field=useragent&facet.field=page_url&facet.field=br_name&facet.field=UsedMemery&facet.field=user_ipaddress&facet.field=dvce_type&facet.field=app_id&wt=json&rows=1500&hl=true&hl.fl=useragent", + "basic_query": "q=*%3A* OR *%3A* OR *%3A*&fq=rs_timestamp:[NOW/DAY-7DAY%20TO%20NOW/DAY%2B1DAY]&facet=true&facet.field=os_name&facet.field=useragent&facet.field=page_url&facet.field=br_name&facet.field=UsedMemery&facet.field=user_ipaddress&facet.field=dvce_type&facet.field=app_id", + "custom": "&fq=app_id:BMW SSA&fq=-app_id:SSA" + }, + "size": 5, + "pages": 300, + "offset": 0, + "group": "default", + "sort": [ + "os_family" + ], + "style": { + "font-size": "12pt" + }, + "overflow": "min-height", + "fields": [ + "os_name", + "useragent", + "page_url", + "br_name", + "UsedMemery", + "user_ipaddress", + "dvce_type", + "app_id" + ], + "highlight": [], + "sortable": false, + "header": true, + "paging": true, + "field_list": true, + "trimFactor": 200, + "normTimes": true, + "spyable": true, + "saveOption": "json", + "exportSize": 1500, + "exportAll": true, + "facet_limit": 100000, + "foundResults": true, + "show_queries": true, + "title": "SSA ï¼Event detail", + "header_field": "app_id", + "body_field": "useragent", + "url_field": "page_url" + } + ] + }, + { + "title": "context time", + "height": "200px", + "editable": true, + "collapse": true, + "collapsable": true, + "panels": [ + { + "error": false, + "span": 6, + "editable": true, + "type": "filtering", + "loadingEditor": false, + "spyable": true + }, + { + "error": false, + "span": 6, + "editable": true, + "type": "query", + "loadingEditor": false, + "query": "*:*", + "pinned": true, + "history": [ + "*:*", + "responseElapsed:[0 TO 20000]", + "responseElapsed:[20000 TO 30000]", + "responseElapsed:[30000 TO *]", + "responseElapsed:[20000 TO 19999]", + "responseElapsed:[0 TO 15000]", + "responseElapsed:[15000 TO 19999]", + "responseElapsed:[20000 TO *]" + ], + "spyable": true, + "remember": 10 + } + ] + } + ], + "editable": true, + "index": { + "interval": "none", + "pattern": "[logstash-]YYYY.MM.DD", + "default": "_all" + }, + "style": "dark", + "failover": false, + "panel_hints": true, + "loader": { + "save_gist": false, + "save_elasticsearch": true, + "save_local": true, + "save_default": true, + "save_temp": true, + "save_temp_ttl_enable": true, + "save_temp_ttl": "30d", + "load_gist": true, + "load_elasticsearch": true, + "load_elasticsearch_size": 20, + "load_local": true, + "hide": false, + "dropdown_collections": false, + "save_as_public": false + }, + "solr": { + "server": "/solr/", + "core_name": "apm3", + "core_list": [ + "PHP_logs", + "apm", + "apm2", + "apm3" + ], + "global_params": "" + }, + "username": "guest" +} \ No newline at end of file diff --git a/src/app/dashboards/Neusoft_platform b/src/app/dashboards/Neusoft_platform new file mode 100644 index 000000000..6dc28aa58 --- /dev/null +++ b/src/app/dashboards/Neusoft_platform @@ -0,0 +1,1981 @@ +{ + "title": "Neusoftï¼å¹³å°äº§å“实时仪表盘", + "services": { + "query": { + "idQueue": [ + 3, + 4 + ], + "list": { + "0": { + "query": "*:*", + "alias": "Risk% ", + "color": "#EA6460", + "id": 0, + "pin": false, + "type": "lucene" + }, + "1": { + "id": 1, + "color": "#E5AC0E", + "query": "*:*", + "alias": "Warning% ", + "pin": false + }, + "2": { + "id": 2, + "color": "#1F78C1", + "query": "*:*", + "alias": "Normal% ", + "pin": false + } + }, + "ids": [ + 0, + 1, + 2 + ] + }, + "filter": { + "idQueue": [ + 1, + 2, + 3 + ], + "list": { + "0": { + "from": "NOW/HOUR-24HOUR", + "to": "NOW/HOUR%2B1HOUR", + "field": "rs_timestamp", + "type": "time", + "fromDateObj": "2017-03-01T05:43:05.568Z", + "toDateObj": "2017-03-02T05:43:05.568Z", + "mandate": "must", + "active": true, + "alias": "", + "id": 0 + } + }, + "ids": [ + 0 + ] + } + }, + "rows": [ + { + "title": "Query and Time Window", + "height": "50px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "error": "", + "span": 8, + "editable": true, + "type": "timepicker", + "loadingEditor": false, + "status": "Stable", + "mode": "relative", + "time_options": [ + "6h", + "12h", + "24h", + "48h", + "72h", + "5d", + "7d", + "10d", + "15d", + "30d", + "90d", + "180d", + "1y", + "3y", + "5y" + ], + "timespan": "24h", + "timefield": "rs_timestamp", + "timeformat": "", + "refresh": { + "enable": true, + "interval": 100, + "min": 3 + }, + "filter_id": 0, + "spyable": true, + "title": "æ—¶é—´è½´" + }, + { + "span": 4, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=user_ipaddress&facet.limit=100000&facet.missing=true&f.user_ipaddress.facet.sort=count&fq=app_id:Platform System", + "custom": "&fq=app_id:Platform System" + }, + "mode": "count", + "field": "user_ipaddress", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 100000, + "sortBy": "count", + "order": "descending", + "style": { + "font-size": "48pt" + }, + "donut": false, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "horizontal", + "chart": "hits", + "counter_pos": "none", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "å¹³å°äº§å“ ï¼ åœ¨çº¿ç”¨æˆ·", + "threshold_first": 3000, + "threshold_second": 5000, + "fontsize": 20 + } + ] + }, + { + "title": "WARNING", + "height": "550px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 3, + "editable": true, + "type": "map", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&rows=0&facet=true&facet.field=ipcode&facet.limit=100000", + "custom": "&fq=app_id:Platform System" + }, + "mode": "count", + "field": "ipcode", + "stats_field": "", + "decimal_points": 0, + "map": "china", + "useNames": false, + "colors": [ + "#A0E2E2", + "#265656" + ], + "size": 100000, + "exclude": [], + "spyable": true, + "index_limit": 0, + "show_queries": true, + "title": "å¹³å°äº§å“ ï¼ ç”¨æˆ·åˆ†å¸ƒ" + }, + { + "span": 6, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=connectElapsed&facet.limit=100000&facet.missing=true&f.connectElapsed.facet.sort=count&fq=app_id:Platform System", + "custom": "&fq=app_id:Platform System" + }, + "mode": "count", + "field": "connectElapsed", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 100000, + "sortBy": "count", + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": false, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "horizontal", + "chart": "dashboard", + "counter_pos": "none", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "å¹³å°äº§å“ï¼ å¥åº·åº¦", + "threshold_first": 5000, + "threshold_second": 10000, + "fontsize": 20 + }, + { + "span": 3, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=user_ipaddress&facet.limit=100000&facet.missing=true&f.user_ipaddress.facet.sort=count&fq=app_id:Platform System", + "custom": "&fq=app_id:Platform System" + }, + "mode": "count", + "field": "user_ipaddress", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 100000, + "sortBy": "count", + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": false, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "horizontal", + "chart": "ebar", + "counter_pos": "none", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "å¹³å°äº§å“ï¼ç”¨æˆ·ç‚¹å‡»TOP5", + "threshold_first": 3000, + "threshold_second": 5000, + "fontsize": 20 + } + ] + }, + { + "title": "Change", + "height": "80px", + "editable": true, + "collapse": true, + "collapsable": true, + "panels": [ + { + "span": 4, + "editable": true, + "type": "ticker", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-03-01T05:43:05.568Z&facet.range.end=2017-03-02T05:43:05.568Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-03-01T04:43:05.568Z&facet.range.end=2017-03-02T04:43:05.568Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-03-01T05:43:05.568Z&facet.range.end=2017-03-02T05:43:05.568Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-03-01T04:43:05.568Z&facet.range.end=2017-03-02T04:43:05.568Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-03-01T05:43:05.568Z&facet.range.end=2017-03-02T05:43:05.568Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-03-01T04:43:05.568Z&facet.range.end=2017-03-02T04:43:05.568Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\n" + }, + "style": { + "font-size": "14pt" + }, + "ago": "1h", + "arrangement": "horizontal", + "spyable": true, + "show_queries": false, + "title": "SSA SYSTEM-Risk chaange(hour)" + }, + { + "span": 4, + "editable": true, + "type": "ticker", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-03-01T05:43:05.568Z&facet.range.end=2017-03-02T05:43:05.568Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-02-28T05:43:05.568Z&facet.range.end=2017-03-01T05:43:05.568Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-03-01T05:43:05.568Z&facet.range.end=2017-03-02T05:43:05.568Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-02-28T05:43:05.568Z&facet.range.end=2017-03-01T05:43:05.568Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-03-01T05:43:05.568Z&facet.range.end=2017-03-02T05:43:05.568Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-02-28T05:43:05.568Z&facet.range.end=2017-03-01T05:43:05.568Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\n" + }, + "style": { + "font-size": "14pt" + }, + "ago": "1d", + "arrangement": "horizontal", + "spyable": true, + "show_queries": true, + "title": "SSA SYSTEM-Risk chaange(day)" + }, + { + "span": 4, + "editable": true, + "type": "ticker", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-03-01T05:43:05.568Z&facet.range.end=2017-03-02T05:43:05.568Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-02-22T05:43:05.568Z&facet.range.end=2017-02-23T05:43:05.568Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-03-01T05:43:05.568Z&facet.range.end=2017-03-02T05:43:05.568Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-02-22T05:43:05.568Z&facet.range.end=2017-02-23T05:43:05.568Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-03-01T05:43:05.568Z&facet.range.end=2017-03-02T05:43:05.568Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-02-22T05:43:05.568Z&facet.range.end=2017-02-23T05:43:05.568Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\n" + }, + "style": { + "font-size": "14pt" + }, + "ago": "1w", + "arrangement": "horizontal", + "spyable": true, + "show_queries": true, + "title": "SSA SYSTEM-Risk chaange(week)" + } + ] + }, + { + "title": "EVENT COUNT", + "height": "200px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 12, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "counts", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=connectElapsed%3A%5B10000%20TO%20*%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/HOUR-24HOUR&facet.range.end=NOW/HOUR%2B1HOUR&facet.range.gap=%2B10MINUTE\nq=connectElapsed%3A%5B5000%20TO%209999%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/HOUR-24HOUR&facet.range.end=NOW/HOUR%2B1HOUR&facet.range.gap=%2B10MINUTE\nq=connectElapsed%3A%5B0%20TO%204999%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/HOUR-24HOUR&facet.range.end=NOW/HOUR%2B1HOUR&facet.range.gap=%2B10MINUTE\n", + "custom": "&fq=app_id:Platform System" + }, + "max_rows": 100000, + "value_field": "connectElapsed", + "group_field": null, + "sum_value": false, + "auto_int": true, + "resolution": 100, + "interval": "10m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": true, + "bars": false, + "stack": true, + "points": false, + "lines": true, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": true, + "show_queries": true, + "tooltip": { + "value_type": "individual", + "query_as_alias": false + }, + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "å¹³å°äº§å“ï¼äº‹åŠ¡ç»Ÿè®¡", + "reverse": 0, + "segment": 3, + "threshold_first": 5000, + "threshold_second": 10000, + "threshold_third": 3000, + "total_first": "%" + } + ] + }, + { + "title": "response time", + "height": "200px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 6, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=responseElapsed%3A%5B5000%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp responseElapsed\nq=responseElapsed%3A%5B3000%20TO%204999%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp responseElapsed\nq=responseElapsed%3A%5B0%20TO%202999%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp responseElapsed\n", + "custom": "&fq=app_id:Platform System&fq=responseElapsed:[0 TO 1000000]" + }, + "max_rows": 100000, + "value_field": "responseElapsed", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "10m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "å¹³å°äº§å“ï¼å“应时间(ms)", + "reverse": 0, + "segment": 3, + "threshold_first": 3000, + "threshold_second": 5000, + "threshold_third": 3000, + "total_first": "%" + }, + { + "span": 6, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=connectElapsed%3A%5B10000%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp connectElapsed\nq=connectElapsed%3A%5B5000%20TO%209999%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp connectElapsed\nq=connectElapsed%3A%5B0%20TO%204999%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp connectElapsed\n", + "custom": "&fq=app_id:Platform System&fq=connectElapsed:[0 TO 100000]" + }, + "max_rows": 100000, + "value_field": "connectElapsed", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "10m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "å¹³å°äº§å“ ï¼æœåŠ¡è¿žæŽ¥æ—¶é—´(MS)", + "reverse": 0, + "segment": 3, + "threshold_first": 5000, + "threshold_second": 10000, + "threshold_third": 3000, + "total_first": "%" + } + ] + }, + { + "title": "RESPONSE", + "height": "200px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 6, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=domElapsed%3A%5B5000%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domElapsed\nq=domElapsed%3A%5B3000%20TO%204999%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domElapsed\nq=domElapsed%3A%5B0%20TO%202999%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domElapsed\n", + "custom": "&fq=-domElapsed:[40000 TO *]&fq=app_id:Platform System" + }, + "max_rows": 100000, + "value_field": "domElapsed", + "group_field": null, + "auto_int": true, + "resolution": 200, + "interval": "5m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 4, + "linewidth": 3, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": false, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "å¹³å°äº§å“ï¼é¡µé¢åŠ è½½æ—¶é—´(ms)", + "reverse": 0, + "segment": 3, + "threshold_first": 3000, + "threshold_second": 5000, + "threshold_third": 3000, + "total_first": "%" + }, + { + "span": 6, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=domContentLoadedElapsed%3A%5B5000%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domContentLoadedElapsed\nq=domContentLoadedElapsed%3A%5B3000%20TO%204999%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domContentLoadedElapsed\nq=domContentLoadedElapsed%3A%5B0%20TO%202999%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domContentLoadedElapsed\n", + "custom": "&fq=app_id:Platform System" + }, + "max_rows": 100000, + "value_field": "domContentLoadedElapsed", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "10m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 0, + "linewidth": 3, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "å¹³å°äº§å“ï¼å†…容加载时间(ms)", + "reverse": 0, + "segment": 3, + "threshold_first": 3000, + "threshold_second": 5000, + "threshold_third": 3000, + "total_first": "%" + } + ] + }, + { + "title": "time", + "height": "200px", + "editable": true, + "collapse": true, + "collapsable": true, + "panels": [] + }, + { + "title": "Message", + "height": "190px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 4, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=cpu%3A%5B80%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp cpu\nq=cpu%3A%5B60%20TO%2079%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp cpu\nq=cpu%3A%5B0%20TO%2059%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp cpu\n", + "custom": "" + }, + "max_rows": 100000, + "reverse": 0, + "segment": 3, + "threshold_first": 60, + "threshold_second": 80, + "threshold_third": 3000, + "value_field": "cpu", + "group_field": null, + "auto_int": true, + "total_first": "%", + "resolution": 100, + "interval": "10m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": false, + "stack": true, + "points": false, + "lines": true, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "individual", + "query_as_alias": false + }, + "title": "å¹³å°äº§å“ï¼CPU 使用率(%)" + }, + { + "span": 4, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=UsedMemery%3A%5B4000%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp UsedMemery\nq=UsedMemery%3A%5B3000%20TO%203999%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp UsedMemery\nq=UsedMemery%3A%5B0%20TO%202999%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp UsedMemery\n", + "custom": "" + }, + "max_rows": 100000, + "value_field": "UsedMemery", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "10m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": false, + "stack": true, + "points": false, + "lines": true, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": false, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "individual", + "query_as_alias": false + }, + "title": "å¹³å°äº§å“ï¼å†…存使用率(MB)", + "reverse": 0, + "segment": 3, + "threshold_first": 3000, + "threshold_second": 4000, + "threshold_third": 3000, + "total_first": "%" + }, + { + "span": 4, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=FreeDiskSpace%3A%5B0%20TO%2099%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp FreeDiskSpace\nq=FreeDiskSpace%3A%5B100%20TO%2019%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp FreeDiskSpace\nq=FreeDiskSpace%3A%5B20%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp FreeDiskSpace\n", + "custom": "" + }, + "max_rows": 100000, + "value_field": "FreeDiskSpace", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "10m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": false, + "stack": true, + "points": false, + "lines": true, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "individual", + "query_as_alias": false + }, + "title": "å¹³å°äº§å“ï¼ç£ç›˜å‰©ä½™(GB)", + "reverse": 1, + "segment": 3, + "threshold_first": 100, + "threshold_second": 20, + "threshold_third": 3000, + "total_first": "%" + } + ] + }, + { + "title": "", + "height": "250px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 4, + "editable": true, + "type": "pies", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=dvce_type&facet.limit=100000&facet.missing=true&f.dvce_type.facet.sort=count&fq=app_id:Platform System", + "custom": "&fq=app_id:Platform System" + }, + "mode": "count", + "field": "dvce_type", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 100000, + "sortBy": "count", + "order": "descending", + "fontsize": 14, + "donut": true, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "vertical", + "RoseType": "area", + "chart": "pie", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#1a93f9", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "eLegend": true, + "title": "å¹³å°äº§å“ ï¼ç”¨æˆ·è®¾å¤‡", + "ylabels": true + }, + { + "span": 4, + "editable": true, + "type": "tagcloud", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=br_name&facet.limit=100000", + "custom": "&fq=app_id:Platform System" + }, + "field": "br_name", + "size": 100000, + "alignment": "horizontal", + "fontScale": 4, + "ignoreStopWords": false, + "spyable": true, + "show_queries": true, + "title": "å¹³å°äº§å“ï¼ ç”¨æˆ·æµè§ˆå™¨" + }, + { + "span": 4, + "editable": true, + "type": "pies", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=metric&facet.limit=10&facet.missing=true&f.metric.facet.sort=count", + "custom": "" + }, + "mode": "count", + "field": "metric", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10, + "sortBy": "count", + "order": "descending", + "fontsize": 12, + "donut": false, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "vertical", + "RoseType": "area", + "chart": "radar", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "å¹³å°äº§å“ï¼ ç”¨æˆ·æµè§ˆé¡µé¢å¯¹æ¯”", + "ylabels": true + } + ] + }, + { + "title": "PIE", + "height": "250px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 6, + "editable": true, + "type": "pies", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=os_name&facet.limit=10&facet.missing=true&f.os_name.facet.sort=count&fq=app_id:Platform System", + "custom": "&fq=app_id:Platform System" + }, + "mode": "count", + "field": "os_name", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10, + "sortBy": "count", + "order": "descending", + "fontsize": 12, + "donut": false, + "tilt": false, + "labels": true, + "ylabels": true, + "logAxis": false, + "arrangement": "vertical", + "RoseType": "area", + "chart": "bars", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "å¹³å°äº§å“ ï¼ ç”¨æˆ·æ“作系统 top 10" + }, + { + "span": 6, + "editable": true, + "type": "pies", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=application&facet.limit=100000&facet.missing=true&f.application.facet.sort=count&fq=app_id:Platform System", + "custom": "&fq=app_id:Platform System" + }, + "mode": "count", + "field": "application", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 100000, + "sortBy": "count", + "order": "descending", + "fontsize": 14, + "donut": false, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "horizontal", + "RoseType": "radius", + "chart": "rosepie", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#1a93f9", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "eLegend": false, + "title": "å¹³å°äº§å“-用户æµè§ˆäº§å“对比", + "ylabels": true + } + ] + }, + { + "title": "IP", + "height": "250px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 6, + "editable": true, + "type": "pies", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=Isp&facet.limit=10&facet.missing=true&f.Isp.facet.sort=count", + "custom": "" + }, + "mode": "count", + "field": "Isp", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10, + "sortBy": "count", + "order": "descending", + "fontsize": 12, + "donut": false, + "tilt": false, + "labels": true, + "ylabels": true, + "logAxis": false, + "arrangement": "vertical", + "RoseType": "area", + "chart": "bar", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#1a75f9", + "#1ab0f9", + "#42d3f0", + "#e59d87", + "#759aa0", + "#dc6b67", + "#efdd79", + "#8dc1aa", + "#ea7d52", + "#8dace7", + "#a6a1e1", + "#FECDA3", + "#FED980", + "#bcf924", + "#f9ac24", + "#8224f9", + "#24e5f9", + "#f96524" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "å¹³å°äº§å“ ï¼ ç”¨æˆ·æ¥æº top 10", + "eLegend": true + }, + { + "span": 6, + "editable": true, + "type": "pies", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=City&facet.limit=10000&facet.missing=true&f.City.facet.sort=count", + "custom": "" + }, + "mode": "count", + "field": "City", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10000, + "sortBy": "count", + "order": "descending", + "fontsize": 12, + "donut": false, + "tilt": false, + "labels": false, + "ylabels": true, + "logAxis": false, + "arrangement": "vertical", + "RoseType": "area", + "chart": "pie", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#1a75f9", + "#1ab0f9", + "#42d3f0", + "#e59d87", + "#759aa0", + "#dc6b67", + "#efdd79", + "#8dc1aa", + "#ea7d52", + "#8dace7", + "#a6a1e1", + "#FECDA3", + "#FED980", + "#bcf924", + "#f9ac24", + "#8224f9", + "#24e5f9", + "#f96524", + "#f4fd8b", + "#b3f457", + "#80f457", + "#60f457", + "#576ef4", + "#579ef4", + "#57cef4", + "#f45b57", + "#7157f4", + "#f457e9", + "#8406e0", + "#2e06e0", + "#a1e006", + "#3de006", + "#06e045", + "#347b93" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "eLegend": true, + "title": "å¹³å°äº§å“-用户城市分布" + } + ] + }, + { + "title": "111", + "height": "550px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 12, + "editable": true, + "type": "china", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=City&facet.limit=10000&facet.missing=true&f.City.facet.sort=count", + "custom": "" + }, + "mode": "count", + "field": "City", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10000, + "sortBy": "count", + "order": "descending", + "logAxis": false, + "chart": "cmap", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "å¹³å°äº§å“ - 地域分布" + } + ] + }, + { + "title": "Detail", + "height": "150px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 12, + "editable": true, + "type": "fullTextSearch", + "loadingEditor": false, + "status": "Stable", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=os_name&facet.field=useragent&facet.field=page_url&facet.field=br_name&facet.field=UsedMemery&facet.field=user_ipaddress&facet.field=dvce_type&facet.field=app_id&wt=json&rows=1500&hl=true&hl.fl=useragent", + "basic_query": "q=*%3A* OR *%3A* OR *%3A*&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=os_name&facet.field=useragent&facet.field=page_url&facet.field=br_name&facet.field=UsedMemery&facet.field=user_ipaddress&facet.field=dvce_type&facet.field=app_id", + "custom": "&fq=app_id:Platform System" + }, + "size": 5, + "pages": 300, + "offset": 0, + "group": "default", + "sort": [ + "os_family" + ], + "style": { + "font-size": "12pt" + }, + "overflow": "min-height", + "fields": [ + "os_name", + "useragent", + "page_url", + "br_name", + "UsedMemery", + "user_ipaddress", + "dvce_type", + "app_id" + ], + "highlight": [], + "sortable": false, + "header": true, + "paging": true, + "field_list": true, + "trimFactor": 200, + "normTimes": true, + "spyable": true, + "saveOption": "json", + "exportSize": 1500, + "exportAll": true, + "facet_limit": 100000, + "foundResults": true, + "show_queries": true, + "title": "å¹³å°äº§å“ï¼è¯¦ç»†ä¿¡æ¯", + "header_field": "app_id", + "body_field": "useragent", + "url_field": "page_url" + } + ] + }, + { + "title": "context time", + "height": "200px", + "editable": true, + "collapse": true, + "collapsable": true, + "panels": [ + { + "error": false, + "span": 6, + "editable": true, + "type": "filtering", + "loadingEditor": false, + "spyable": true + }, + { + "error": false, + "span": 6, + "editable": true, + "type": "query", + "loadingEditor": false, + "query": "*:*", + "pinned": true, + "history": [ + "*:*", + "responseElapsed:[0 TO 20000]", + "responseElapsed:[20000 TO 30000]", + "responseElapsed:[30000 TO *]", + "responseElapsed:[20000 TO 19999]", + "responseElapsed:[0 TO 15000]", + "responseElapsed:[15000 TO 19999]", + "responseElapsed:[20000 TO *]" + ], + "spyable": true, + "remember": 10 + } + ] + } + ], + "editable": true, + "index": { + "interval": "none", + "pattern": "[logstash-]YYYY.MM.DD", + "default": "_all" + }, + "style": "light", + "failover": false, + "panel_hints": true, + "loader": { + "save_gist": false, + "save_elasticsearch": true, + "save_local": true, + "save_default": true, + "save_temp": true, + "save_temp_ttl_enable": true, + "save_temp_ttl": "30d", + "load_gist": true, + "load_elasticsearch": true, + "load_elasticsearch_size": 20, + "load_local": true, + "hide": false, + "dropdown_collections": false, + "save_as_public": false + }, + "solr": { + "server": "http://101.201.82.138:9983/solr/", + "core_name": "apm3", + "core_list": [ + "PHP_logs", + "apm", + "apm2", + "apm3", + "new", + "new_core", + "test" + ], + "global_params": "" + }, + "username": "guest" +} \ No newline at end of file diff --git a/src/app/dashboards/default-mobile.json b/src/app/dashboards/default-mobile.json new file mode 100644 index 000000000..401731d6b --- /dev/null +++ b/src/app/dashboards/default-mobile.json @@ -0,0 +1,1228 @@ +{ + "title": "RealSight APM (RealTime) 实时状æ€ç›‘控", + "services": { + "query": { + "idQueue": [ + 1, + 2, + 3, + 4 + ], + "list": { + "0": { + "query": "*:*", + "alias": "", + "color": "#7EB26D", + "id": 0, + "pin": false, + "type": "lucene" + } + }, + "ids": [ + 0 + ] + }, + "filter": { + "idQueue": [ + 1, + 2, + 3, + 4 + ], + "list": { + "0": { + "from": "NOW/MINUTE-15MINUTE", + "to": "NOW/MINUTE%2B1MINUTE", + "field": "rs_timestamp", + "type": "time", + "fromDateObj": "2016-08-27T06:38:31.990Z", + "toDateObj": "2016-08-27T06:53:31.990Z", + "mandate": "must", + "active": true, + "alias": "", + "id": 0 + } + }, + "ids": [ + 0 + ] + } + }, + "rows": [ + { + "title": "检索", + "height": "50px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "error": "", + "span": 5, + "editable": true, + "type": "timepicker", + "loadingEditor": false, + "status": "Stable", + "mode": "relative", + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "7d", + "30d", + "90d", + "1y", + "5y" + ], + "timespan": "12h", + "timefield": "rs_timestamp", + "timeformat": "", + "refresh": { + "enable": true, + "interval": 3, + "min": 1 + }, + "filter_id": 0, + "spyable": true, + "title": "时间范围" + }, + { + "error": false, + "span": 3, + "editable": true, + "group": [ + "default" + ], + "type": "query", + "label": "Search", + "history": [ + "*:*" + ], + "remember": 10, + "pinned": true, + "query": "*:*", + "title": "模糊查询", + "spyable": true, + "def_type": "" + }, + { + "span": 4, + "editable": true, + "type": "hits", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&fq=rs_timestamp:[NOW/MINUTE-15MINUTE%20TO%20NOW/MINUTE%2B1MINUTE]&wt=json&rows=0\n", + "basic_query": "", + "custom": "" + }, + "style": { + "font-size": "26pt" + }, + "arrangement": "horizontal", + "chart": "total", + "counter_pos": "above", + "donut": false, + "tilt": false, + "labels": true, + "spyable": true, + "title": "访问总é‡", + "show_queries": true + } + ] + }, + { + "title": "æ¡ä»¶è¿‡æ»¤", + "height": "50px", + "editable": true, + "collapse": true, + "collapsable": true, + "panels": [ + { + "error": false, + "span": 8, + "editable": true, + "spyable": true, + "group": [ + "default" + ], + "type": "filtering" + } + ] + }, + { + "title": "页é¢è®¿é—®çжæ€", + "height": "150px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 12, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "count", + "time_field": "rs_timestamp", + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-1HOUR%20TO%20NOW/HOUR-1HOUR]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/HOUR-1HOUR&facet.range.end=NOW/HOUR%2B1HOUR&facet.range.gap=%2B30SECOND\n", + "custom": "" + }, + "max_rows": 100000, + "value_field": "polarityCount_i", + "group_field": "polarity_s", + "auto_int": true, + "resolution": 100, + "interval": "10s", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 0, + "linewidth": 3, + "timezone": "browser", + "spyable": true, + "zoomlinks": true, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "实时页é¢è®¿é—®", + "lines_smooth": false, + "show_queries": true + } + ] + }, + { + + + "title": "终端访问状æ€", + "height": "150px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 12, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "count", + "time_field": "rs_timestamp", + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-1HOUR%20TO%20NOW/HOUR-1HOUR]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/HOUR-1HOUR&facet.range.end=NOW/HOUR%2B1HOUR&facet.range.gap=%2B30SECOND\n", + "custom": "&fq=osType:ios" + }, + "max_rows": 100000, + "value_field": "polarityCount_i", + "group_field": "polarity_s", + "auto_int": true, + "resolution": 100, + "interval": "10s", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 0, + "linewidth": 3, + "timezone": "browser", + "spyable": true, + "zoomlinks": true, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "实时终端访问", + "lines_smooth": false, + "show_queries": true + } + ] + }, + { + "title": "页é¢åˆ†æž", + "height": "250px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 2, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=rs_timestamp:[NOW/MINUTE-15MINUTE%20TO%20NOW/MINUTE%2B1MINUTE]&facet=true&facet.field=br_name&facet.limit=10&facet.missing=true", + "custom": "" + }, + "mode": "count", + "field": "br_name", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": true, + "size": 10, + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": true, + "tilt": false, + "labels": true, + "arrangement": "horizontal", + "chart": "pie", + "counter_pos": "none", + "lastColor": "rgb(110,208,224)", + "spyable": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "title": "æµè§ˆå™¨", + "logAxis": false, + "show_queries": true + }, + { + "span": 2, + "editable": true, + "type": "tagcloud", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=rs_timestamp:[NOW/MINUTE-15MINUTE%20TO%20NOW/MINUTE%2B1MINUTE]&facet=true&facet.field=user_ipaddress&facet.limit=20", + "custom": "" + }, + "field": "user_ipaddress", + "size": 20, + "alignment": "vertical and horizontal", + "fontScale": 1, + "spyable": true, + "show_queries": true, + "title": "用户IP" + }, + { + "span": 3, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=rs_timestamp:[NOW/MINUTE-15MINUTE%20TO%20NOW/MINUTE%2B1MINUTE]&facet=true&facet.field=user_ipaddress&facet.limit=10&facet.missing=true", + "custom": "" + }, + "mode": "count", + "field": "user_ipaddress", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10, + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": false, + "tilt": false, + "labels": true, + "arrangement": "horizontal", + "chart": "bar", + "counter_pos": "none", + "lastColor": "rgb(80,134,66)", + "spyable": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "title": "最高访问é‡IPå‰åå", + "logAxis": false, + "show_queries": true + }, + { + "span": 2, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=rs_timestamp:[NOW/MINUTE-15MINUTE%20TO%20NOW/MINUTE%2B1MINUTE]&facet=true&facet.field=os_name&facet.limit=10&facet.missing=true", + "custom": "" + }, + "mode": "count", + "field": "os_name", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": true, + "size": 10, + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": true, + "tilt": false, + "labels": true, + "arrangement": "horizontal", + "chart": "pie", + "counter_pos": "none", + "lastColor": "rgb(110,208,224)", + "spyable": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "title": "æ“作系统", + "logAxis": false, + "show_queries": true + }, + { + "span": 3, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=rs_timestamp:[NOW/MINUTE-15MINUTE%20TO%20NOW/MINUTE%2B1MINUTE]&facet=true&facet.field=responseElapsed&facet.limit=10&facet.missing=true", + "custom": "" + }, + "mode": "count", + "field": "responseElapsed", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10, + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": false, + "tilt": false, + "labels": true, + "arrangement": "horizontal", + "chart": "bar", + "counter_pos": "none", + "lastColor": "rgb(80,134,66)", + "spyable": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "title": "请求å“应时间统计", + "logAxis": false, + "show_queries": true + } + ] + }, + { + + "title": "终端分æž", + "height": "250px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 2, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=rs_timestamp:[NOW/MINUTE-15MINUTE%20TO%20NOW/MINUTE%2B1MINUTE]&facet=true&facet.field=deviceManufacturer&facet.limit=10&facet.missing=true", + "custom": "" + }, + "mode": "count", + "field": "deviceManufacturer", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": true, + "size": 10, + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": true, + "tilt": false, + "labels": true, + "arrangement": "horizontal", + "chart": "pie", + "counter_pos": "none", + "lastColor": "rgb(110,208,224)", + "spyable": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "title": "终端生产商", + "logAxis": false, + "show_queries": true + }, + { + "span": 2, + "editable": true, + "type": "tagcloud", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=rs_timestamp:[NOW/MINUTE-15MINUTE%20TO%20NOW/MINUTE%2B1MINUTE]&facet=true&facet.field=carrier&facet.limit=20", + "custom": "" + }, + "field": "carrier", + "size": 20, + "alignment": "vertical and horizontal", + "fontScale": 1, + "spyable": true, + "show_queries": true, + "title": "ISPæä¾›å•†" + }, + { + "span": 3, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=rs_timestamp:[NOW/MINUTE-15MINUTE%20TO%20NOW/MINUTE%2B1MINUTE]&facet=true&facet.field=deviceModel&facet.limit=10&facet.missing=true", + "custom": "" + }, + "mode": "count", + "field": "deviceModel", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10, + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": false, + "tilt": false, + "labels": true, + "arrangement": "horizontal", + "chart": "bar", + "counter_pos": "none", + "lastColor": "rgb(80,134,66)", + "spyable": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "title": "最常用设备类型å‰åå", + "logAxis": false, + "show_queries": true + }, + { + "span": 2, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=rs_timestamp:[NOW/MINUTE-15MINUTE%20TO%20NOW/MINUTE%2B1MINUTE]&facet=true&facet.field=osType&facet.limit=10&facet.missing=true", + "custom": "" + }, + "mode": "count", + "field": "osType", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": true, + "size": 10, + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": true, + "tilt": false, + "labels": true, + "arrangement": "horizontal", + "chart": "pie", + "counter_pos": "none", + "lastColor": "rgb(110,208,224)", + "spyable": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "title": "终端OS", + "logAxis": false, + "show_queries": true + }, + { + "span": 3, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=rs_timestamp:[NOW/MINUTE-15MINUTE%20TO%20NOW/MINUTE%2B1MINUTE]&facet=true&facet.field=deviceModel&facet.limit=10&facet.missing=true", + "custom": "" + }, + "mode": "count", + "field": "deviceModel", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10, + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": false, + "tilt": false, + "labels": true, + "arrangement": "horizontal", + "chart": "bar", + "counter_pos": "none", + "lastColor": "rgb(80,134,66)", + "spyable": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "title": "设备类型统计", + "logAxis": false, + "show_queries": true + } + ] + + }, + { + "title": "明细", + "height": "150px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 12, + "editable": true, + "type": "table", + "loadingEditor": false, + "status": "Stable", + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&fq=rs_timestamp:[NOW/MINUTE-15MINUTE%20TO%20NOW/MINUTE%2B1MINUTE]&sort=rs_timestamp desc&wt=json&rows=500", + "basic_query": "q=*%3A*&df=id&fq=rs_timestamp:[NOW/MINUTE-15MINUTE%20TO%20NOW/MINUTE%2B1MINUTE]&sort=rs_timestamp desc", + "custom": "" + }, + "size": 100, + "pages": 5, + "offset": 0, + "sort": [ + "id", + "desc" + ], + "group": "default", + "style": { + "font-size": "9pt" + }, + "overflow": "min-height", + "fields": [ + "app_id", + "rs_timestamp", + "doctype_s", + "connectElapsed", + "responseElapsed", + "page_urlhost", + "page_urlpath", + "useragent" + ], + "highlight": [], + "sortable": true, + "header": true, + "paging": true, + "field_list": true, + "trimFactor": 300, + "normTimes": true, + "spyable": false, + "saveOption": "json", + "exportSize": 500, + "exportAll": true, + "displayLinkIcon": true, + "imageFields": [], + "imgFieldWidth": "auto", + "imgFieldHeight": "85px", + "title": "实时请求明细", + "important_fields": [ + "app_id", + "event_id", + "rs_timestamp", + "doctype_s", + "id", + "connectElapsed", + "responseElapsed", + "page_urlhost", + "page_urlpath", + "useragent" + ], + "show_queries": true + } + ] + } + ], + "editable": true, + "index": { + "interval": "none", + "pattern": "[logstash-]YYYY.MM.DD", + "default": "_all" + }, + "style": "dark", + "failover": false, + "panel_hints": true, + "loader": { + "save_gist": false, + "save_elasticsearch": true, + "save_local": true, + "save_default": true, + "save_temp": true, + "save_temp_ttl_enable": true, + "save_temp_ttl": "30d", + "load_gist": true, + "load_elasticsearch": true, + "load_elasticsearch_size": 20, + "load_local": true, + "hide": false, + "dropdown_collections": false + }, + "solr": { + "server": "/solr/", + "core_name": "apm2", + "core_list": [ + "apm2_shard1_replica1" + ], + "global_params": "&df=id" + } +} \ No newline at end of file diff --git a/src/app/dashboards/default-nts.json b/src/app/dashboards/default-nts.json index 6e0433c3c..e6be4b984 100644 --- a/src/app/dashboards/default-nts.json +++ b/src/app/dashboards/default-nts.json @@ -81,21 +81,7 @@ "tilt": false, "labels": true, "spyable": true, - "title": "Total Hits", - "show_queries": true, - "metrics": [ - { - "type": "count", - "field": "id", - "decimalDigits": 0, - "label": "", - "value": "0" - } - ], - "refresh": { - "enable": false, - "interval": 2 - } + "title": "Total Hits" } ] }, @@ -195,9 +181,9 @@ "dropdown_collections": false }, "solr": { - "server": "/api/apollo/solr/", - "core_name": "logs", + "server": "/solr/", + "core_name": "collection1", "core_list": [], "global_params": "" } -} +} \ No newline at end of file diff --git a/src/app/dashboards/default-ts.json b/src/app/dashboards/default-ts.json index 0609d65f7..17f1c2738 100644 --- a/src/app/dashboards/default-ts.json +++ b/src/app/dashboards/default-ts.json @@ -128,21 +128,7 @@ "tilt": false, "labels": true, "spyable": true, - "title": "Total Hits", - "show_queries": true, - "metrics": [ - { - "type": "count", - "field": "id", - "decimalDigits": 0, - "label": "", - "value": "0" - } - ], - "refresh": { - "enable": false, - "interval": 2 - } + "title": "Total Hits" } ] }, @@ -311,9 +297,9 @@ "dropdown_collections": false }, "solr": { - "server": "/api/apollo/solr/", - "core_name": "logs", + "server": "/solr/", + "core_name": "collection1", "core_list": [], "global_params": "" } -} +} \ No newline at end of file diff --git a/src/app/dashboards/default.json b/src/app/dashboards/default.json old mode 100755 new mode 100644 index 27c41233c..e726f2a08 --- a/src/app/dashboards/default.json +++ b/src/app/dashboards/default.json @@ -1,366 +1,2412 @@ -{ - "title": "Basic Dashboard With Pointers", - "services": { - "query": { - "idQueue": [ - 1, - 2, - 3, - 4 +{ + "title": "Neusoftï¼å¹³å°äº§å“实时仪表盘", + "services": { + "query": { + "idQueue": [ + 3, + 4 + ], + "list": { + "0": { + "query": "*:*", + "alias": "Risk% ", + "color": "#EA6460", + "id": 0, + "pin": false, + "type": "lucene" + }, + "1": { + "id": 1, + "color": "#E5AC0E", + "query": "*:*", + "alias": "Warning% ", + "pin": false + }, + "2": { + "id": 2, + "color": "#1a93f9", + "query": "*:*", + "alias": "Normal% ", + "pin": false + } + }, + "ids": [ + 0, + 1, + 2 + ] + }, + "filter": { + "idQueue": [ + 1, + 2, + 3 + ], + "list": { + "0": { + "from": "NOW/HOUR-24HOUR", + "to": "NOW/HOUR%2B1HOUR", + "field": "rs_timestamp", + "type": "time", + "fromDateObj": "2017-05-17T02:45:48.274Z", + "toDateObj": "2017-05-18T02:45:48.275Z", + "mandate": "must", + "active": true, + "alias": "", + "id": 0 + } + }, + "ids": [ + 0 + ] + } + }, + "rows": [ + { + "title": "Query and Time Window", + "height": "50px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "error": "", + "span": 8, + "editable": true, + "type": "timepicker", + "loadingEditor": false, + "status": "Stable", + "mode": "relative", + "time_options": [ + "1h", + "2h", + "6h", + "12h", + "24h", + "48h", + "72h", + "5d", + "7d", + "10d", + "15d", + "30d", + "90d", + "180d", + "1y", + "3y", + "5y" + ], + "timespan": "24h", + "timefield": "rs_timestamp", + "timeformat": "", + "refresh": { + "enable": false, + "interval": 100, + "min": 3 + }, + "filter_id": 0, + "spyable": true, + "title": "æ—¶é—´è½´", + "display": "block", + "icon": "icon-caret-down" + }, + { + "span": 4, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=user_ipaddress&facet.limit=100000&facet.missing=true&f.user_ipaddress.facet.sort=count&fq=app_id:Platform System", + "custom": "&fq=app_id:Platform System" + }, + "mode": "count", + "field": "user_ipaddress", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 100000, + "sortBy": "count", + "order": "descending", + "style": { + "font-size": "48pt" + }, + "donut": false, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "horizontal", + "chart": "hits", + "counter_pos": "none", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "å¹³å°äº§å“ ï¼ åœ¨çº¿ç”¨æˆ·", + "threshold_first": 3000, + "threshold_second": 5000, + "fontsize": 20, + "title_defined": false, + "display": "block", + "icon": "icon-caret-down", + "linkage_id": "a" + } + ] + }, + { + "title": "WARNING", + "height": "0px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 3, + "editable": true, + "type": "map", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 ], - "list": { - "0": { - "query": "*", - "alias": "", - "color": "#7EB26D", - "id": 0, - "pin": false, - "type": "lucene" - } - }, + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&rows=0&facet=true&facet.field=ipcode&facet.limit=100000", + "custom": "&fq=app_id:Platform System" + }, + "mode": "count", + "field": "ipcode", + "stats_field": "", + "decimal_points": 0, + "map": "china", + "useNames": false, + "colors": [ + "#A0E2E2", + "#265656" + ], + "size": 100000, + "exclude": [], + "spyable": true, + "index_limit": 0, + "show_queries": true, + "title": "å¹³å°äº§å“ ï¼ ç”¨æˆ·åˆ†å¸ƒ", + "display": "block", + "icon": "icon-caret-down", + "height": "500", + "linkage_id": "a" + }, + { + "span": 6, + "editable": true, + "type": "gauge", + "loadingEditor": false, + "queries": { + "mode": "all", "ids": [ - 0 - ] + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=responseElapsed&facet.limit=10000&facet.missing=true&f.responseElapsed.facet.sort=count&fq=app_id:Platform System", + "custom": "&fq=app_id:Platform System" + }, + "mode": "count", + "field": "responseElapsed", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10000, + "sortBy": "count", + "threshold_first": 3000, + "threshold_second": 5000, + "order": "descending", + "style": { + "font-size": "10pt" + }, + "fontsize": 20, + "title_defined": true, + "donut": false, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "horizontal", + "chart": "gauge", + "counter_pos": "none", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "å¹³å°äº§å“ï¼ å¥åº·åº¦", + "display": "block", + "icon": "icon-caret-down", + "height": "500", + "linkage_id": "a" }, - "filter": { - "idQueue": [ - 1, - 2 + { + "span": 3, + "editable": true, + "type": "pies", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=user_ipaddress&facet.limit=5&facet.missing=true&f.user_ipaddress.facet.sort=count&fq=app_id:Platform System", + "custom": "&fq=app_id:Platform System" + }, + "mode": "count", + "field": "user_ipaddress", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 5, + "sortBy": "count", + "order": "descending", + "fontsize": 20, + "donut": false, + "tilt": false, + "labels": true, + "ylabels": true, + "logAxis": false, + "arrangement": "vertical", + "RoseType": "area", + "chart": "ebar", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "å¹³å°äº§å“ï¼ç”¨æˆ·ç‚¹å‡»TOP5", + "display": "block", + "icon": "icon-caret-down", + "height": "500", + "solrFq": "fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]", + "linkage_id": "a", + "value_sort": "rs_timestamp", + "defaulttimestamp": true + } + ] + }, + { + "title": "", + "height": "0px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 12, + "editable": true, + "type": "stacking", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=redirectElapsed cacheElapsed dnsElapsed tcpElapsed requestElapsed responseElapsed domElapsed loadEventElapsed%3A%5B*%20TO%20*%5D&wt=json&sort=rs_timestamp%20asc&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp redirectElapsed cacheElapsed dnsElapsed tcpElapsed requestElapsed responseElapsed domElapsed loadEventElapsed\n", + "custom": "&fq=domElapsed:[0 TO 10000000]&fq=responseElapsed :[0 TO 10000000]&fq=cacheElapsed :[0 TO 10000000]&fq=requestElapsed:[0 TO 10000000]&fq=dnsElapsed :[0 TO 10000000]&fq=redirectElapsed :[0 TO 10000000]&fq=tcpElapsed :[0 TO 10000000]&fq=loadEventElapsed:[0 TO 10000000]" + }, + "max_rows": 100000, + "reverse": 0, + "segment": 4, + "threshold_first": 1000, + "threshold_second": 2000, + "threshold_third": 3000, + "value_field": "redirectElapsed cacheElapsed dnsElapsed tcpElapsed requestElapsed responseElapsed domElapsed loadEventElapsed", + "group_field": null, + "auto_int": true, + "total_first": "%", + "fontsize": 20, + "field_color": "#209bf8", + "resolution": 100, + "interval": "10m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 0, + "linewidth": 3, + "timezone": "browser", + "spyable": true, + "zoomlinks": true, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": true, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "chart": "mean", + "title": "å¹³å°äº§å“-WebView平凿€§èƒ½åˆ†æž", + "chartColors": [ + "#FF4500", + "#ff7a00", + "#f48a52", + "#f4d352", + "#8cf452", + "#52f4c0", + "#1a93f9", + "#2fd7ee" + ], + "label": true, + "value_sort": "rs_timestamp", + "linkage": false, + "display": "block", + "icon": "icon-caret-down", + "height": "150px", + "isEN": false, + "linkage_id": "a" + } + ] + }, + { + "title": "å¹³å°äº§å“", + "height": "0px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 12, + "editable": true, + "type": "stacking", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 ], - "list": { - "0": { - "from": "2014-04-02T05:07:22.216Z", - "to": "2014-04-02T05:22:22.216Z", - "field": "event_timestamp", - "type": "time", - "mandate": "must", - "active": true, - "alias": "", - "id": 0 - } - }, + "query": "q=redirectElapsed cacheElapsed dnsElapsed tcpElapsed requestElapsed responseElapsed domElapsed loadEventElapsed%3A%5B*%20TO%20*%5D&wt=json&sort=rs_timestamp%20asc&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp redirectElapsed cacheElapsed dnsElapsed tcpElapsed requestElapsed responseElapsed domElapsed loadEventElapsed\n", + "custom": "&fq=domElapsed:[0 TO 10000000]&fq=responseElapsed :[0 TO 10000000]&fq=cacheElapsed :[0 TO 10000000]&fq=requestElapsed:[0 TO 10000000]&fq=dnsElapsed :[0 TO 10000000]&fq=redirectElapsed :[0 TO 10000000]&fq=tcpElapsed :[0 TO 10000000]&fq=loadEventElapsed:[0 TO 10000000]" + }, + "max_rows": 100000, + "reverse": 0, + "segment": 4, + "threshold_first": 1000, + "threshold_second": 2000, + "threshold_third": 3000, + "value_field": "redirectElapsed cacheElapsed dnsElapsed tcpElapsed requestElapsed responseElapsed domElapsed loadEventElapsed", + "group_field": null, + "auto_int": true, + "total_first": "%", + "fontsize": 20, + "field_color": "#209bf8", + "resolution": 100, + "value_sort": "rs_timestamp", + "interval": "10m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 0, + "linewidth": 3, + "chart": "stacking", + "chartColors": [ + "#FF4500", + "#ff7a00", + "#f48a52", + "#f4d352", + "#8cf452", + "#52f4c0", + "#1a93f9", + "#2fd7ee" + ], + "timezone": "browser", + "spyable": true, + "zoomlinks": true, + "bars": true, + "stack": true, + "label": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": true, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "å¹³å°äº§å“-WebView性能分æž", + "linkage": false, + "display": "block", + "icon": "icon-caret-down", + "height": "300", + "isEN": false, + "linkage_id": "a" + } + ] + }, + { + "title": "EVENT COUNT", + "height": "0px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 12, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "counts", + "queries": { + "mode": "all", "ids": [ - 0 - ] + 0, + 1, + 2 + ], + "query": "q=connectElapsed%3A%5B10000%20TO%20*%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/HOUR-24HOUR&facet.range.end=NOW/HOUR%2B1HOUR&facet.range.gap=%2B10MINUTE\nq=connectElapsed%3A%5B5000%20TO%209999%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/HOUR-24HOUR&facet.range.end=NOW/HOUR%2B1HOUR&facet.range.gap=%2B10MINUTE\nq=connectElapsed%3A%5B0%20TO%204999%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/HOUR-24HOUR&facet.range.end=NOW/HOUR%2B1HOUR&facet.range.gap=%2B10MINUTE\n", + "custom": "&fq=app_id:Platform System" + }, + "max_rows": 100000, + "value_field": "connectElapsed", + "group_field": null, + "sum_value": false, + "auto_int": true, + "resolution": 100, + "interval": "10m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": true, + "bars": false, + "stack": true, + "points": false, + "lines": true, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": true, + "show_queries": true, + "tooltip": { + "value_type": "individual", + "query_as_alias": false + }, + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "å¹³å°äº§å“ï¼äº‹åŠ¡ç»Ÿè®¡", + "reverse": 0, + "segment": 3, + "threshold_first": 5000, + "threshold_second": 10000, + "threshold_third": 3000, + "total_first": "%", + "display": "block", + "icon": "icon-caret-down", + "height": "200", + "linkage_id": "a" } + ] }, - "rows": [ + { + "title": "response time", + "height": "0px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ { - "title": "Overview", - "height": "50px", - "editable": true, - "collapse": false, - "collapsable": true, - "panels": [ - { - "error": false, - "span": 6, - "editable": true, - "type": "text", - "loadingEditor": false, - "status": "Stable", - "mode": "markdown", - "content": "You may be seeing a message that says Solr is not reachable or that the collection is not found. Click on _Configure Dashboard_ (cog icon) on the top right and set the Solr server and collection. By default, we have configured the dashboard to point to server _http://localhost:8983_ and collection _collection1_. You can also choose how many rows you want to have in the dashboard. \n\nTo configure what panels appear in a specific row, click on the _Configure Row_ (cog icon) at the far left of the row.\n\nEach panel can be configured by clicking on _Configure_ (cog icon) near the top right of the panel (just to the left of the panel type). The span of the panel determines its width; each row has width 12, and each panel can take up all or part of this span.\n\nAfter reading these _text panels_ (which are useful for presenting information about a dashboard), you can delete them by clicking on the \"x\" towards the top right of the panel.", - "style": {}, - "title": "Configure Dashboard" - }, - { - "error": false, - "span": 6, - "editable": true, - "group": [ - "default" - ], - "type": "text", - "status": "Stable", - "mode": "markdown", - "content": "In the row below, we have put in a _time picker_ and a _search bar._ Banana is primarily designed for time series data, and we expect every dashboard to have a time picker. You will also almost always have a search bar for user searches. \n\nBelow that there is a hidden row that contains a _filtering_ module, which is used to configure global filter queries. You will almost certainly want to have one. Clicking on any facet in the terms module will filter results by that value. You can modify each filter once it is created; you can change the value and/or choose between \"must\", \"must not\" and \"either.\"\n\nClick on the right-facing triangle to the far left of the row to _Expand Row_. You can click on the upward-facing triangle on any row in order to _Hide Row._", - "style": {}, - "title": "Timestamps, Queries and Filters" - } - ] + "span": 6, + "editable": true, + "type": "histobar", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=responseElapsed%3A%5B*%20TO%20*%5D&wt=json&sort=rs_timestamp%20asc&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp responseElapsed\n", + "custom": "&fq=app_id:Platform System&fq=responseElapsed:[0 TO 1000000]" + }, + "max_rows": 100000, + "reverse": 0, + "segment": 4, + "threshold_first": 3000, + "threshold_second": 5000, + "threshold_third": 3000, + "group_field": null, + "auto_int": true, + "area": false, + "total_first": "%", + "fontsize": 12, + "field_color": "#2ce41b", + "resolution": 100, + "value_sort": "rs_timestamp", + "interval": "10m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 0, + "linewidth": 3, + "chart": "histobar", + "chartColors": [ + "#f48a52", + "#f4d352", + "#ccf452", + "#8cf452", + "#3cee2b", + "#f467d8", + "#1a93f9", + "#2fd7ee" + ], + "timezone": "browser", + "spyable": true, + "linkage": false, + "zoomlinks": true, + "bars": true, + "stack": true, + "label": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "å¹³å°äº§å“ï¼å“应时间(ms)", + "value_field": "responseElapsed", + "average": false, + "defaulttimestamp": true, + "display": "block", + "icon": "icon-caret-down", + "height": "230", + "linkage_id": "a", + "isEN": false }, { - "title": "Query and Time Window", - "height": "50px", - "editable": true, - "collapse": false, - "collapsable": true, - "panels": [ - { - "error": "", - "span": 6, - "editable": true, - "type": "timepicker", - "loadingEditor": false, - "status": "Stable", - "mode": "relative", - "spyable" : true, - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d", - "90d", - "1y", - "5y" - ], - "timespan": "15m", - "timefield": "event_timestamp", - "timeformat": "", - "refresh": { - "enable": false, - "interval": 30, - "min": 3 - }, - "filter_id": 0, - "title": "Time Window" - }, - { - "error": false, - "span": 6, - "editable": true, - "spyable" : true, - "group": [ - "default" - ], - "type": "query", - "label": "Search", - "history": [ - "*" - ], - "remember": 10, - "pinned": true, - "query": "*", - "title": "Search", - "def_type": "" - } - ] + "span": 6, + "editable": true, + "type": "histobar", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=connectElapsed%3A%5B*%20TO%20*%5D&wt=json&sort=rs_timestamp%20asc&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp connectElapsed\n", + "custom": "&fq=app_id:Platform System&fq=connectElapsed:[0 TO 100000]" + }, + "max_rows": 100000, + "reverse": 0, + "segment": 4, + "threshold_first": 5000, + "threshold_second": 10000, + "threshold_third": 3000, + "group_field": null, + "auto_int": true, + "area": false, + "total_first": "%", + "fontsize": 12, + "field_color": "#2ce41b", + "resolution": 100, + "value_sort": "rs_timestamp", + "interval": "10m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 0, + "linewidth": 3, + "chart": "histobar", + "chartColors": [ + "#f48a52", + "#f4d352", + "#ccf452", + "#8cf452", + "#3cee2b", + "#f467d8", + "#1a93f9", + "#2fd7ee" + ], + "timezone": "browser", + "spyable": true, + "linkage": false, + "zoomlinks": true, + "bars": true, + "stack": true, + "label": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "value_field": "connectElapsed", + "title": "å¹³å°äº§å“ ï¼æœåŠ¡è¿žæŽ¥æ—¶é—´(MS)", + "average": false, + "defaulttimestamp": true, + "display": "block", + "icon": "icon-caret-down", + "height": "230", + "linkage_id": "a", + "isEN": false + } + ] + }, + { + "title": "RESPONSE", + "height": "0px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 6, + "editable": true, + "type": "histobar", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=domElapsed%3A%5B*%20TO%20*%5D&wt=json&sort=rs_timestamp%20asc&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domElapsed\n", + "custom": "&fq=app_id:Platform System&fq=domElapsed:[0 TO 1000000]" + }, + "max_rows": 100000, + "reverse": 0, + "segment": 4, + "threshold_first": 3000, + "threshold_second": 5000, + "threshold_third": 3000, + "group_field": null, + "auto_int": true, + "area": false, + "total_first": "%", + "fontsize": 12, + "field_color": "#2ce41b", + "resolution": 100, + "value_sort": "rs_timestamp", + "interval": "10m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 0, + "linewidth": 3, + "chart": "histobar", + "chartColors": [ + "#f48a52", + "#f4d352", + "#ccf452", + "#8cf452", + "#3cee2b", + "#f467d8", + "#1a93f9", + "#2fd7ee" + ], + "timezone": "browser", + "spyable": true, + "linkage": false, + "zoomlinks": true, + "bars": true, + "stack": true, + "label": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "å¹³å°äº§å“ï¼é¡µåŠ è½½æ—¶é—´(ms)", + "value_field": "domElapsed", + "average": false, + "defaulttimestamp": true, + "display": "block", + "icon": "icon-caret-down", + "height": "230", + "linkage_id": "a", + "isEN": false }, { - "title": "Filters", - "height": "50px", - "editable": true, - "collapse": true, - "collapsable": true, - "panels": [ - { - "error": false, - "span": 12, - "editable": true, - "spyable" : true, - "group": [ - "default" - ], - "type": "filtering" - } - ] + "span": 6, + "editable": true, + "type": "histobar", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=domContentLoadedElapsed%3A%5B*%20TO%20*%5D&wt=json&sort=rs_timestamp%20asc&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domContentLoadedElapsed\n", + "custom": "&fq=app_id:Platform System" + }, + "max_rows": 100000, + "reverse": 0, + "segment": 4, + "threshold_first": 3000, + "threshold_second": 5000, + "threshold_third": 3000, + "group_field": null, + "auto_int": true, + "area": false, + "total_first": "%", + "fontsize": 12, + "field_color": "#2ce41b", + "resolution": 100, + "value_sort": "rs_timestamp", + "interval": "10m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 0, + "linewidth": 3, + "chart": "histobar", + "chartColors": [ + "#f48a52", + "#f4d352", + "#ccf452", + "#8cf452", + "#3cee2b", + "#f467d8", + "#1a93f9", + "#2fd7ee" + ], + "timezone": "browser", + "spyable": true, + "linkage": false, + "zoomlinks": true, + "bars": true, + "stack": true, + "label": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "value_field": "domContentLoadedElapsed", + "title": "å¹³å°äº§å“ï¼å†…容加载时间(ms)", + "average": false, + "defaulttimestamp": true, + "display": "block", + "icon": "icon-caret-down", + "height": "230", + "linkage_id": "a", + "isEN": false + } + ] + }, + { + "title": "Message", + "height": "0px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 4, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=cpu%3A%5B80%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp cpu\nq=cpu%3A%5B60%20TO%2079%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp cpu\nq=cpu%3A%5B0%20TO%2059%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp cpu\n", + "custom": "" + }, + "max_rows": 100000, + "reverse": 0, + "segment": 3, + "threshold_first": 60, + "threshold_second": 80, + "threshold_third": 3000, + "value_field": "cpu", + "group_field": null, + "auto_int": true, + "total_first": "%", + "resolution": 100, + "interval": "10m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": false, + "stack": true, + "points": false, + "lines": true, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "individual", + "query_as_alias": false + }, + "title": "å¹³å°äº§å“ï¼CPU 使用率(%)", + "display": "block", + "icon": "icon-caret-down", + "height": "190", + "linkage_id": "a" }, { - "title": "Facets, Histogram and Table", - "height": "150px", - "editable": true, - "collapse": false, - "collapsable": true, - "panels": [ - { - "error": false, - "span": 12, - "editable": true, - "group": [ - "default" - ], - "type": "text", - "status": "Stable", - "mode": "markdown", - "content": "Without knowing about your data, I cannot fully configure the panels I have provided below. However, I have provided you with some starting points, assuming that your time field is \"event_timestamp\" and that there is a field called \"message\" that you wish to facet on in order to view the top terms that appear in the \"message\" field and their frequency. If there is no data, these panels will be empty, and may give an error.\n\nThe _histogram_ panel allows you to plot either _counts_ or a specific field's (integer) _values_ across time. If you go to _Configure_, the panel allows you to set the type of chart and what variable is plotted (if choosing the _values_ option). Moreover, when plotting values, you can specify a _group by_ field which will produce multiple charts. You can modify the time window for the entire page from within the histogram panel.\n\nThe _terms_ panel is great for visualizing facets--as pie charts, bar charts or tables. Clicking on a term will create a global filter query restricting the result set (across all panels within the page) to the field value that is selected. You could have many such panels depending on the number of fields you choose to facet on.\n\nThe *table* panel at the bottom provides you a detailed view of search results. It has attempted to list your fields to the left; select a few to view them in the table. You can sort by any field. Click on a particular row to expand the resulting document that was returned.", - "style": {}, - "title": "Facets, Histogram and Table" - } - ] + "span": 4, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=UsedMemery%3A%5B4000%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp UsedMemery\nq=UsedMemery%3A%5B3000%20TO%203999%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp UsedMemery\nq=UsedMemery%3A%5B0%20TO%202999%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp UsedMemery\n", + "custom": "" + }, + "max_rows": 100000, + "value_field": "UsedMemery", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "10m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": false, + "stack": true, + "points": false, + "lines": true, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": false, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "individual", + "query_as_alias": false + }, + "title": "å¹³å°äº§å“ï¼å†…存使用率(MB)", + "reverse": 0, + "segment": 3, + "threshold_first": 3000, + "threshold_second": 4000, + "threshold_third": 3000, + "total_first": "%", + "display": "block", + "icon": "icon-caret-down", + "height": "190", + "linkage_id": "a" }, { - "title": "Graph", - "height": "250px", - "editable": true, - "collapse": false, - "collapsable": true, - "panels": [ - { - "span": 6, - "editable": true, - "type": "histogram", - "loadingEditor": false, - "mode": "count", - "queries": { - "mode": "all", - "ids": [ - 0 - ], - "query": "q=*&wt=json&rows=0", - "custom": "" - }, - "max_rows": 100000, - "value_field": null, - "group_field": null, - "auto_int": true, - "resolution": 100, - "interval": "10s", - "intervals": [ - "auto", - "1s", - "1m", - "5m", - "10m", - "30m", - "1h", - "3h", - "12h", - "1d", - "1w", - "1M", - "1y" - ], - "fill": 0, - "linewidth": 3, - "timezone": "browser", - "spyable": true, - "zoomlinks": true, - "bars": true, - "stack": true, - "points": false, - "lines": false, - "legend": true, - "x-axis": true, - "y-axis": true, - "percentage": false, - "interactive": true, - "options": true, - "tooltip": { - "value_type": "cumulative", - "query_as_alias": false - }, - "title": "Event Counts" - }, - { - "error": false, - "span": 6, - "editable": true, - "group": [ - "default" - ], - "type": "terms", - "queries": { - "mode": "all", - "ids": [ - 0 - ], - "query": "q=*&wt=json&rows=0&fq=event_timestamp:[2014-04-02T05:07:22.000Z%20TO%202014-04-02T05:22:22.000Z]&facet=true&facet.field=message&facet.range=event_timestamp&facet.range.start=2014-04-02T05:07:22.000Z&facet.range.end=2014-04-02T05:22:22.000Z&facet.range.gap=%2B1DAY&facet.limit=100" - }, - "field": "message", - "exclude": [], - "missing": false, - "other": false, - "size": 100, - "order": "count", - "style": { - "font-size": "10pt" - }, - "donut": true, - "tilt": true, - "labels": false, - "arrangement": "horizontal", - "chart": "pie", - "counter_pos": "none", - "title": "Message Terms", - "spyable": true, - "time_field": "event_timestamp" - } - ] + "span": 4, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=FreeDiskSpace%3A%5B0%20TO%2099%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp FreeDiskSpace\nq=FreeDiskSpace%3A%5B100%20TO%2019%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp FreeDiskSpace\nq=FreeDiskSpace%3A%5B20%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp FreeDiskSpace\n", + "custom": "" + }, + "max_rows": 100000, + "value_field": "FreeDiskSpace", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "10m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": false, + "stack": true, + "points": false, + "lines": true, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "individual", + "query_as_alias": false + }, + "title": "å¹³å°äº§å“ï¼ç£ç›˜å‰©ä½™(GB)", + "reverse": 1, + "segment": 3, + "threshold_first": 100, + "threshold_second": 20, + "threshold_third": 3000, + "total_first": "%", + "display": "block", + "icon": "icon-caret-down", + "height": "190", + "linkage_id": "a" + } + ] + }, + { + "title": "", + "height": "250px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 4, + "editable": true, + "type": "pies", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=dvce_type&facet.limit=100000&facet.missing=true&f.dvce_type.facet.sort=count&fq=app_id:Platform System", + "custom": "&fq=app_id:Platform System" + }, + "mode": "count", + "field": "dvce_type", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 100000, + "sortBy": "count", + "order": "descending", + "fontsize": 14, + "donut": true, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "vertical", + "RoseType": "area", + "chart": "pie", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#1a93f9", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "eLegend": true, + "title": "å¹³å°äº§å“ ï¼ç”¨æˆ·è®¾å¤‡", + "ylabels": true, + "display": "block", + "icon": "icon-caret-down", + "height": "250", + "solrFq": "fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]", + "linkage_id": "a", + "value_sort": "rs_timestamp", + "defaulttimestamp": true }, { - "title": "Events", - "height": "650px", - "editable": true, - "collapse": false, - "collapsable": true, - "panels": [ - { - "error": false, - "span": 12, - "editable": true, - "group": [ - "default" - ], - "type": "table", - "size": 100, - "pages": 5, - "offset": 0, - "sort": [ - "id", - "desc" - ], - "style": { - "font-size": "9pt" - }, - "overflow": "min-height", - "fields": [ - "message" - ], - "highlight": [], - "sortable": true, - "header": true, - "paging": true, - "spyable": true, - "queries": { - "mode": "all", - "ids": [ - 0 - ], - "query": "q=*&wt=json&rows=500&fq=event_timestamp:[2014-04-02T05:07:22.000Z%20TO%202014-04-02T05:22:22.000Z]&sort=id desc" - }, - "field_list": true, - "status": "Stable", - "trimFactor": 300, - "normTimes": true, - "title": "Events", - "time_field": "event_timestamp" - } - ] + "span": 4, + "editable": true, + "type": "tagcloud", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=br_name&facet.limit=100000", + "custom": "&fq=app_id:Platform System" + }, + "field": "br_name", + "size": 100000, + "alignment": "horizontal", + "fontScale": 4, + "ignoreStopWords": false, + "spyable": true, + "show_queries": true, + "title": "å¹³å°äº§å“ï¼ ç”¨æˆ·æµè§ˆå™¨", + "display": "block", + "icon": "icon-caret-down", + "height": "250", + "linkage_id": "a" + }, + { + "span": 4, + "editable": true, + "type": "pies", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=metric&facet.limit=10&facet.missing=true&f.metric.facet.sort=count", + "custom": "" + }, + "mode": "count", + "field": "metric", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10, + "sortBy": "count", + "order": "descending", + "fontsize": 12, + "donut": false, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "vertical", + "RoseType": "area", + "chart": "radar", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "å¹³å°äº§å“ï¼ ç”¨æˆ·æµè§ˆé¡µé¢å¯¹æ¯”", + "ylabels": true, + "display": "block", + "icon": "icon-caret-down", + "height": "250", + "solrFq": "fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]", + "linkage_id": "a", + "value_sort": "rs_timestamp", + "defaulttimestamp": true } - ], - "editable": true, - "index": { - "interval": "none", - "pattern": "[logstash-]YYYY.MM.DD", - "default": "_all" + ] }, - "style": "light", - "failover": false, - "panel_hints": true, - "loader": { - "save_gist": true, - "save_elasticsearch": true, - "save_local": true, - "save_default": true, - "save_temp": true, - "save_temp_ttl_enable": true, - "save_temp_ttl": "30d", - "load_gist": true, - "load_elasticsearch": true, - "load_elasticsearch_size": 20, - "load_local": true, - "hide": false + { + "title": "PIE", + "height": "0px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 6, + "editable": true, + "type": "pies", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=os_name&facet.limit=10&facet.missing=true&f.os_name.facet.sort=count&fq=app_id:Platform System", + "custom": "&fq=app_id:Platform System" + }, + "mode": "count", + "field": "os_name", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10, + "sortBy": "count", + "order": "ascending", + "fontsize": 12, + "donut": false, + "tilt": false, + "labels": true, + "ylabels": true, + "logAxis": false, + "arrangement": "vertical", + "RoseType": "area", + "chart": "liquidfill", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "å¹³å°äº§å“ ï¼ ç”¨æˆ·æ“作系统 top 10", + "display": "block", + "icon": "icon-caret-down", + "height": "250", + "solrFq": "fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]", + "linkage_id": "a", + "value_sort": "rs_timestamp", + "defaulttimestamp": true + }, + { + "span": 6, + "editable": true, + "type": "pies", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=application&facet.limit=100000&facet.missing=true&f.application.facet.sort=count&fq=app_id:Platform System", + "custom": "&fq=app_id:Platform System" + }, + "mode": "count", + "field": "application", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 100000, + "sortBy": "count", + "order": "descending", + "fontsize": 14, + "donut": false, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "horizontal", + "RoseType": "radius", + "chart": "rosepie", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#1a93f9", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "eLegend": false, + "title": "å¹³å°äº§å“-用户æµè§ˆäº§å“对比", + "ylabels": true, + "display": "block", + "icon": "icon-caret-down", + "height": "250", + "solrFq": "fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]", + "linkage_id": "a", + "value_sort": "rs_timestamp", + "defaulttimestamp": true + } + ] }, - "solr": { - "server": "/solr/", - "core_name": "collection1", - "core_list": [], - "global_params": "" + { + "title": "IP", + "height": "0px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 6, + "editable": true, + "type": "pies", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=Isp&facet.limit=10&facet.missing=true&f.Isp.facet.sort=count", + "custom": "" + }, + "mode": "count", + "field": "Isp", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10, + "sortBy": "count", + "order": "ascending", + "fontsize": 12, + "donut": false, + "tilt": false, + "labels": true, + "ylabels": true, + "logAxis": false, + "arrangement": "vertical", + "RoseType": "area", + "chart": "bars", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#1a75f9", + "#1ab0f9", + "#42d3f0", + "#e59d87", + "#759aa0", + "#dc6b67", + "#efdd79", + "#8dc1aa", + "#ea7d52", + "#8dace7", + "#a6a1e1", + "#FECDA3", + "#FED980", + "#bcf924", + "#f9ac24", + "#8224f9", + "#24e5f9", + "#f96524" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "å¹³å°äº§å“ ï¼ ç”¨æˆ·æ¥æº top 10", + "eLegend": true, + "display": "block", + "icon": "icon-caret-down", + "height": "250", + "solrFq": "fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]", + "linkage_id": "a", + "value_sort": "rs_timestamp", + "defaulttimestamp": true + }, + { + "span": 6, + "editable": true, + "type": "pies", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=City&facet.limit=10000&facet.missing=true&f.City.facet.sort=count", + "custom": "" + }, + "mode": "count", + "field": "City", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10000, + "sortBy": "count", + "order": "descending", + "fontsize": 12, + "donut": false, + "tilt": false, + "labels": false, + "ylabels": true, + "logAxis": false, + "arrangement": "vertical", + "RoseType": "area", + "chart": "pie", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#1a75f9", + "#1ab0f9", + "#42d3f0", + "#e59d87", + "#759aa0", + "#dc6b67", + "#efdd79", + "#8dc1aa", + "#ea7d52", + "#8dace7", + "#a6a1e1", + "#FECDA3", + "#FED980", + "#bcf924", + "#f9ac24", + "#8224f9", + "#24e5f9", + "#f96524", + "#f4fd8b", + "#b3f457", + "#80f457", + "#60f457", + "#576ef4", + "#579ef4", + "#57cef4", + "#f45b57", + "#7157f4", + "#f457e9", + "#8406e0", + "#2e06e0", + "#a1e006", + "#3de006", + "#06e045", + "#347b93" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "eLegend": true, + "title": "å¹³å°äº§å“-用户城市分布", + "display": "block", + "icon": "icon-caret-down", + "height": "250", + "solrFq": "fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]", + "linkage_id": "a", + "value_sort": "rs_timestamp", + "defaulttimestamp": true + } + ] + }, + { + "title": "111", + "height": "0px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 12, + "editable": true, + "type": "china", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=City&facet.limit=10000&facet.missing=true&f.City.facet.sort=count", + "custom": "" + }, + "mode": "count", + "field": "City", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10000, + "sortBy": "count", + "order": "descending", + "logAxis": false, + "chart": "cmap", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "å¹³å°äº§å“ - 国内访问分布", + "display": "block", + "icon": "icon-caret-down", + "height": "500", + "linkage_id": "a", + "isEN": false + } + ] + }, + { + "title": "3d", + "height": "350px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 12, + "editable": true, + "type": "glmap", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=ipLocation_s&facet.limit=10000&facet.missing=true&f.ipLocation_s.facet.sort=count", + "custom": "" + }, + "mode": "count", + "field": "ipLocation_s", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10000, + "sortBy": "count", + "order": "descending", + "fontsize": 12, + "donut": false, + "tilt": false, + "display": "block", + "icon": "icon-caret-down", + "labels": true, + "ylabels": true, + "linkage_id": "a", + "logAxis": false, + "arrangement": "vertical", + "RoseType": "area", + "chart": "earth1", + "exportSize": 10000, + "value_sort": "rs_timestamp", + "defaulttimestamp": true, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "height": "350", + "title": "å¹³å°äº§å“ - å…¨çƒè®¿é—®åˆ†å¸ƒ" + } + ] + }, + { + "title": "Detail", + "height": "0px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 12, + "editable": true, + "type": "fullTextSearch", + "loadingEditor": false, + "status": "Stable", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=os_name&facet.field=useragent&facet.field=page_url&facet.field=br_name&facet.field=UsedMemery&facet.field=user_ipaddress&facet.field=dvce_type&facet.field=app_id&wt=json&rows=1500&hl=true&hl.fl=useragent", + "basic_query": "q=*%3A* OR *%3A* OR *%3A*&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=os_name&facet.field=useragent&facet.field=page_url&facet.field=br_name&facet.field=UsedMemery&facet.field=user_ipaddress&facet.field=dvce_type&facet.field=app_id", + "custom": "&fq=app_id:Platform System" + }, + "size": 5, + "pages": 300, + "offset": 0, + "group": "default", + "sort": [ + "os_family" + ], + "style": { + "font-size": "12pt" + }, + "overflow": "min-height", + "fields": [ + "os_name", + "useragent", + "page_url", + "br_name", + "UsedMemery", + "user_ipaddress", + "dvce_type", + "app_id" + ], + "highlight": [], + "sortable": false, + "header": true, + "paging": true, + "field_list": true, + "trimFactor": 200, + "normTimes": true, + "spyable": true, + "saveOption": "json", + "exportSize": 1500, + "exportAll": true, + "facet_limit": 100000, + "foundResults": true, + "show_queries": true, + "title": "å¹³å°äº§å“ï¼è¯¦ç»†ä¿¡æ¯", + "header_field": "app_id", + "body_field": "useragent", + "url_field": "page_url", + "display": "block", + "icon": "icon-caret-down", + "height": "150", + "linkage_id": "a" + } + ] + }, + { + "title": "context time", + "height": "200px", + "editable": true, + "collapse": true, + "collapsable": true, + "panels": [ + { + "error": false, + "span": 6, + "editable": true, + "type": "filtering", + "loadingEditor": false, + "spyable": true, + "display": "block", + "icon": "icon-caret-down" + }, + { + "error": false, + "span": 6, + "editable": true, + "type": "query", + "loadingEditor": false, + "query": "*:*", + "pinned": true, + "history": [ + "*:*", + "responseElapsed:[0 TO 20000]", + "responseElapsed:[20000 TO 30000]", + "responseElapsed:[30000 TO *]", + "responseElapsed:[20000 TO 19999]", + "responseElapsed:[0 TO 15000]", + "responseElapsed:[15000 TO 19999]", + "responseElapsed:[20000 TO *]" + ], + "spyable": true, + "remember": 10, + "display": "block", + "icon": "icon-caret-down", + "linkage_id": "a" + } + ] } + ], + "editable": false, + "index": { + "interval": "none", + "pattern": "[logstash-]YYYY.MM.DD", + "default": "_all" + }, + "style": "dark", + "failover": false, + "panel_hints": true, + "loader": { + "save_gist": false, + "save_elasticsearch": true, + "save_local": true, + "save_default": true, + "save_temp": true, + "save_temp_ttl_enable": true, + "save_temp_ttl": "30d", + "load_gist": true, + "load_elasticsearch": true, + "load_elasticsearch_size": 20, + "load_local": true, + "hide": false, + "dropdown_collections": false, + "save_as_public": false + }, + "solr": { + "server": "http://101.201.82.138:6983/solr/", + "core_name": "apm3", + "core_list": [ + "PHP_logs", + "TV_test", + "apm", + "apm2", + "apm3", + "apm_demo", + "mobile" + ], + "global_params": "" + }, + "username": "guest", + "filterids": [ + 0 + ], + "isstyle": "dark", + "hide_head": false, + "language": 1, + "row_controller": false, + "searchEnable": false, + "searchID": 0, + "isSearch": false, + "mute": false, + "en_cn": false, + "alarm": false, + "loading": false, + "enable_linkage": true, + "linkage_id": "a" } diff --git a/src/app/dashboards/lucidworks-searchlogs.json b/src/app/dashboards/default.twitter.json similarity index 68% rename from src/app/dashboards/lucidworks-searchlogs.json rename to src/app/dashboards/default.twitter.json index a734b981e..6683ca1cd 100644 --- a/src/app/dashboards/lucidworks-searchlogs.json +++ b/src/app/dashboards/default.twitter.json @@ -1,9 +1,12 @@ { - "title": "Fusion Logs", + "title": "RealSight APM Realtime Dashboard", "services": { "query": { "idQueue": [ - 1 + 1, + 2, + 3, + 4 ], "list": { "0": { @@ -20,52 +23,46 @@ ] }, "filter": { - "idQueue": [], + "idQueue": [ + 1, + 2, + 3, + 4 + ], "list": { "0": { - "from": "NOW/DAY-2DAY", - "to": "NOW/DAY%2B1DAY", - "field": "timestamp_tdt", + "from": "NOW/HOUR-1HOUR", + "to": "NOW/HOUR%2B1HOUR", + "field": "timestamp", "type": "time", - "fromDateObj": "2014-08-27T17:30:33.070Z", - "toDateObj": "2014-08-29T17:30:33.071Z", + "fromDateObj": "2015-06-01T20:12:37.820Z", + "toDateObj": "2015-06-01T21:12:37.820Z", "mandate": "must", "active": true, "alias": "", "id": 0 - }, - "1": { - "type": "exists", - "field": "file_s", - "mandate": "mustNot", - "active": true, - "alias": "", - "id": 1 } }, "ids": [ - 1, 0 ] } }, "rows": [ { - "title": "Options", + "title": "Query and Time Window", "height": "50px", "editable": true, "collapse": false, "collapsable": true, "panels": [ { - "title": "Set time span", "error": "", "span": 5, "editable": true, - "group": [ - "default" - ], "type": "timepicker", + "loadingEditor": false, + "status": "Stable", "mode": "relative", "time_options": [ "5m", @@ -74,79 +71,119 @@ "6h", "12h", "24h", - "2d", "7d", "30d", + "90d", "1y", "5y" ], - "timespan": "2d", - "timefield": "timestamp_tdt", + "timespan": "15m", + "timefield": "timestamp", "timeformat": "", "refresh": { - "enable": false, - "interval": 600, - "min": 3 + "enable": true, + "interval": 3, + "min": 1 }, "filter_id": 0, - "status": "Stable" + "spyable": true, + "title": "Time Window" }, { "error": false, - "span": 4, + "span": 3, "editable": true, + "group": [ + "default" + ], "type": "query", - "loadingEditor": false, - "query": "*:*", - "pinned": true, + "label": "Search", "history": [ "*:*" ], "remember": 10, - "title": "Search" + "pinned": true, + "query": "*:*", + "title": "Search", + "spyable": true, + "def_type": "" }, { - "error": false, - "span": 3, + "span": 4, "editable": true, - "type": "text", + "type": "hits", "loadingEditor": false, - "status": "Stable", - "mode": "markdown", - "content": "You have a few choices:\n\n* [Blank Dashboard](index.html#/dashboard/file/blank.json) I don't have much data yet, please extract some basics for me\n* [LucidWorks Fusion Signals](index.html#/dashboard/file/lucidworks-signals.json) Explore the Lucidworks Fusion Signals collection\n", - "style": {}, - "title": "Explore Dashboards" + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&fq=timestamp:[NOW/HOUR-1HOUR%20TO%20NOW/HOUR%2B1HOUR]&wt=json&rows=0\n", + "basic_query": "", + "custom": "" + }, + "style": { + "font-size": "14pt" + }, + "arrangement": "horizontal", + "chart": "total", + "counter_pos": "above", + "donut": false, + "tilt": false, + "labels": true, + "spyable": true, + "title": "Total Hits", + "show_queries": true } ] }, { - "title": "Graph", - "height": "350px", + "title": "Filters", + "height": "50px", + "editable": true, + "collapse": true, + "collapsable": true, + "panels": [ + { + "error": false, + "span": 8, + "editable": true, + "spyable": true, + "group": [ + "default" + ], + "type": "filtering" + } + ] + }, + { + "title": "Histogram row", + "height": "150px", "editable": true, "collapse": false, "collapsable": true, "panels": [ { - "span": 4, + "span": 12, "editable": true, "type": "histogram", "loadingEditor": false, "mode": "count", - "time_field": "timestamp_tdt", + "time_field": "timestamp", "queries": { "mode": "all", "ids": [ 0 ], - "query": "q=*%3A*&wt=json&rows=0&fq=timestamp_tdt:[NOW/DAY-2DAY%20TO%20NOW/DAY%2B1DAY]&facet=true&facet.range=timestamp_tdt&facet.range.start=NOW/DAY-2DAY&facet.range.end=NOW/DAY%2B1DAY&facet.range.gap=%2B30MINUTE", + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=timestamp:[NOW/HOUR-1HOUR%20TO%20NOW/HOUR-1HOUR]&facet=true&facet.range=timestamp&facet.range.start=NOW/HOUR-1HOUR&facet.range.end=NOW/HOUR%2B1HOUR&facet.range.gap=%2B30SECOND\n", "custom": "" }, "max_rows": 100000, - "value_field": null, - "group_field": null, + "value_field": "polarityCount_i", + "group_field": "polarity_s", "auto_int": true, "resolution": 100, - "interval": "30m", + "interval": "30s", "intervals": [ "auto", "1s", @@ -171,7 +208,6 @@ "stack": true, "points": false, "lines": false, - "lines_smooth": false, "legend": true, "x-axis": true, "y-axis": true, @@ -182,11 +218,21 @@ "value_type": "cumulative", "query_as_alias": false }, - "title": "Log Messages" - }, + "title": "Tweet Histogram", + "lines_smooth": false, + "show_queries": true + } + ] + }, + { + "title": "Graph", + "height": "250px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ { - "error": false, - "span": 4, + "span": 2, "editable": true, "type": "terms", "loadingEditor": false, @@ -195,30 +241,29 @@ "ids": [ 0 ], - "query": "q=*%3A*&wt=json&rows=0&fq=timestamp_tdt:[NOW/DAY-2DAY%20TO%20NOW/DAY%2B1DAY]&facet=true&facet.field=level_s&facet.limit=10", + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=timestamp:[NOW/HOUR-1HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=language_s&facet.limit=10&facet.missing=true", "custom": "" }, "mode": "count", - "field": "level_s", + "field": "language_s", "stats_field": "", "decimal_points": 0, "exclude": [], "missing": false, - "other": false, + "other": true, "size": 10, "order": "descending", "style": { "font-size": "10pt" }, - "donut": false, + "donut": true, "tilt": false, "labels": true, - "arrangement": "vertical", - "chart": "bar", - "counter_pos": "below", + "arrangement": "horizontal", + "chart": "pie", + "counter_pos": "none", + "lastColor": "rgb(110,208,224)", "spyable": true, - "title": "Log Level", - "lastColor": "", "chartColors": [ "#7EB26D", "#EAB839", @@ -276,114 +321,38 @@ "#BADFF4", "#F9D9F9", "#DEDAF7" - ] + ], + "title": "Languages", + "logAxis": false, + "show_queries": true }, + + + { - "error": false, - "span": 4, + "span": 3, "editable": true, - "type": "terms", + "type": "tagcloud", "loadingEditor": false, "queries": { "mode": "all", "ids": [ 0 ], - "query": "q=*%3A*&wt=json&rows=0&fq=timestamp_tdt:[NOW/DAY-2DAY%20TO%20NOW/DAY%2B1DAY]&facet=true&facet.field=file_t&facet.limit=10", + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=timestamp:[NOW/HOUR-1HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=screenName_s&facet.limit=20", "custom": "" }, - "mode": "count", - "field": "file_t", - "stats_field": "", - "decimal_points": 0, - "exclude": [], - "missing": false, - "other": false, - "size": 10, - "order": "descending", - "style": { - "font-size": "10pt" - }, - "donut": false, - "tilt": false, - "labels": true, - "arrangement": "vertical", - "chart": "bar", - "counter_pos": "below", + "field": "screenName_s", + "size": 20, + "alignment": "vertical and horizontal", + "fontScale": 1, "spyable": true, - "title": "File", - "lastColor": "", - "chartColors": [ - "#7EB26D", - "#EAB839", - "#6ED0E0", - "#EF843C", - "#E24D42", - "#1F78C1", - "#BA43A9", - "#705DA0", - "#508642", - "#CCA300", - "#447EBC", - "#C15C17", - "#890F02", - "#0A437C", - "#6D1F62", - "#584477", - "#B7DBAB", - "#F4D598", - "#70DBED", - "#F9BA8F", - "#F29191", - "#82B5D8", - "#E5A8E2", - "#AEA2E0", - "#629E51", - "#E5AC0E", - "#64B0C8", - "#E0752D", - "#BF1B00", - "#0A50A1", - "#962D82", - "#614D93", - "#9AC48A", - "#F2C96D", - "#65C5DB", - "#F9934E", - "#EA6460", - "#5195CE", - "#D683CE", - "#806EB7", - "#3F6833", - "#967302", - "#2F575E", - "#99440A", - "#58140C", - "#052B51", - "#511749", - "#3F2B5B", - "#E0F9D7", - "#FCEACA", - "#CFFAFF", - "#F9E2D2", - "#FCE2DE", - "#BADFF4", - "#F9D9F9", - "#DEDAF7" - ] - } - ] - }, - { - "title": "Description", - "height": "150px", - "editable": true, - "collapse": false, - "collapsable": true, - "panels": [ + "show_queries": true, + "title": "Screen Names" + }, + { - "error": false, - "span": 3, + "span": 2, "editable": true, "type": "terms", "loadingEditor": false, @@ -392,11 +361,11 @@ "ids": [ 0 ], - "query": "q=*%3A*&wt=json&rows=0&fq=timestamp_tdt:[NOW/DAY-2DAY%20TO%20NOW/DAY%2B1DAY]&facet=true&facet.field=host_s&facet.limit=10", + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=timestamp:[NOW/HOUR-1HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=screenName_s&facet.limit=10&facet.missing=true", "custom": "" }, "mode": "count", - "field": "host_s", + "field": "screenName_s", "stats_field": "", "decimal_points": 0, "exclude": [], @@ -410,12 +379,11 @@ "donut": false, "tilt": false, "labels": true, - "arrangement": "vertical", + "arrangement": "horizontal", "chart": "bar", - "counter_pos": "below", + "counter_pos": "none", + "lastColor": "rgb(80,134,66)", "spyable": true, - "title": "Host", - "lastColor": "", "chartColors": [ "#7EB26D", "#EAB839", @@ -473,11 +441,14 @@ "#BADFF4", "#F9D9F9", "#DEDAF7" - ] + ], + "title": "Top Tweeters", + "logAxis": false, + "show_queries": true }, + { - "error": false, - "span": 4, + "span": 2, "editable": true, "type": "terms", "loadingEditor": false, @@ -486,16 +457,16 @@ "ids": [ 0 ], - "query": "q=*%3A*&wt=json&rows=0&fq=timestamp_tdt:[NOW/DAY-2DAY%20TO%20NOW/DAY%2B1DAY]&facet=true&facet.field=port_s&facet.limit=10", + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=timestamp:[NOW/HOUR-1HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=originalposter_s&facet.limit=10&facet.missing=true", "custom": "" }, "mode": "count", - "field": "port_s", + "field": "originalposter_s", "stats_field": "", "decimal_points": 0, "exclude": [], - "missing": true, - "other": true, + "missing": false, + "other": false, "size": 10, "order": "descending", "style": { @@ -506,8 +477,8 @@ "labels": true, "arrangement": "horizontal", "chart": "bar", - "counter_pos": "above", - "lastColor": "", + "counter_pos": "none", + "lastColor": "rgb(80,134,66)", "spyable": true, "chartColors": [ "#7EB26D", @@ -567,11 +538,13 @@ "#F9D9F9", "#DEDAF7" ], - "title": "Ports" + "title": "Original Tweeters", + "logAxis": false, + "show_queries": true }, + { - "error": false, - "span": 4, + "span": 2, "editable": true, "type": "terms", "loadingEditor": false, @@ -580,17 +553,17 @@ "ids": [ 0 ], - "query": "q=*%3A*&wt=json&rows=0&fq=timestamp_tdt:[NOW/DAY-2DAY%20TO%20NOW/DAY%2B1DAY]&facet=true&facet.field=method_t&facet.limit=10", + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=timestamp:[NOW/HOUR-1HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=lang&facet.limit=150&facet.missing=true", "custom": "" }, "mode": "count", - "field": "method_t", + "field": "language_s", "stats_field": "", "decimal_points": 0, "exclude": [], - "missing": true, - "other": true, - "size": 10, + "missing": false, + "other": false, + "size": 150, "order": "descending", "style": { "font-size": "10pt" @@ -599,8 +572,8 @@ "tilt": false, "labels": true, "arrangement": "horizontal", - "chart": "bar", - "counter_pos": "above", + "chart": "table", + "counter_pos": "none", "lastColor": "", "spyable": true, "chartColors": [ @@ -661,87 +634,92 @@ "#F9D9F9", "#DEDAF7" ], - "title": "Method" + "title": "Languages", + "logAxis": false, + "show_queries": true } ] }, { - "title": "Events", - "height": "350px", + "title": "Table", + "height": "150px", "editable": true, "collapse": false, "collapsable": true, "panels": [ { - "title": "All events", - "error": false, "span": 12, "editable": true, - "group": [ - "default" - ], "type": "table", + "loadingEditor": false, + "status": "Stable", + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&fq=timestamp:[NOW/HOUR-1HOUR%20TO%20NOW/HOUR%2B1HOUR]&wt=json&rows=50", + "basic_query": "q=*%3A*&df=id&fq=timestamp:[NOW/HOUR-1HOUR%20TO%20NOW/HOUR%2B1HOUR]", + "custom": "" + }, "size": 100, - "pages": 10, + "pages": 5, "offset": 0, "sort": [ - "timestamp_tdt", + "timestamp", "desc" ], + "group": "default", "style": { "font-size": "9pt" }, "overflow": "min-height", "fields": [ - "timestamp_tdt", - "level_s", - "message_s", - "host_s", - "port_s", - "line_i", - "message_t", - "method_t", - "stacktrace_t", - "file_t", - "class_t" + "timestamp", + "screenName_s", + "text_t", + "language_s" ], "highlight": [], "sortable": true, "header": true, "paging": true, - "spyable": true, - "queries": { - "mode": "all", - "ids": [ - 0 - ], - "query": "q=*%3A*&fq=timestamp_tdt:[NOW/DAY-2DAY%20TO%20NOW/DAY%2B1DAY]&sort=timestamp_tdt desc&wt=json&rows=1000", - "basic_query": "q=*%3A*&fq=timestamp_tdt:[NOW/DAY-2DAY%20TO%20NOW/DAY%2B1DAY]&sort=timestamp_tdt desc" - }, "field_list": true, - "status": "Stable", "trimFactor": 300, "normTimes": true, - "time_field": "timestamp_tdt", + "spyable": false, "saveOption": "json", - "exportSize": 1000, + "exportSize": 50, "exportAll": true, "displayLinkIcon": true, "imageFields": [], "imgFieldWidth": "auto", - "imgFieldHeight": "85px" + "imgFieldHeight": "85px", + "title": "Tweets", + "important_fields": [ + "_version_", + "timestamp", + "doctype_s", + "id", + "language_s", + "screenName_s", + "tag_s", + "tag_ss", + "text_t" + ], + "show_queries": true } ] } ], "editable": true, - "failover": false, "index": { "interval": "none", "pattern": "[logstash-]YYYY.MM.DD", - "default": "NO_TIME_FILTER_OR_INDEX_PATTERN_NOT_MATCHED" + "default": "_all" }, - "style": "light", + "style": "dark", + "failover": false, "panel_hints": true, "loader": { "save_gist": false, @@ -759,17 +737,11 @@ "dropdown_collections": false }, "solr": { - "server": "/api/apollo/solr/", - "core_name": "logs", + "server": "/solr/", + "core_name": "tweets", "core_list": [ - null, - null, - null, - null, - null, - null, - null, - null - ] + "tweets" + ], + "global_params": "&df=id" } } diff --git a/src/app/dashboards/defaultback.json b/src/app/dashboards/defaultback.json new file mode 100644 index 000000000..522ffcb28 --- /dev/null +++ b/src/app/dashboards/defaultback.json @@ -0,0 +1,1459 @@ +{ + "title": "BMW Chinaï¼Application Monitoring Dashboard", + "services": { + "query": { + "idQueue": [ + 3, + 4 + ], + "list": { + "0": { + "query": "responseElapsed:[20000 TO *]", + "alias": "Risk", + "color": "#EA6460", + "id": 0, + "pin": false, + "type": "lucene" + }, + "1": { + "id": 1, + "color": "#E5AC0E", + "query": "responseElapsed:[15000 TO 19999]", + "alias": "Warning", + "pin": false + }, + "2": { + "id": 2, + "color": "#508642", + "query": "responseElapsed:[0 TO 15000]", + "alias": "Normal", + "pin": false + } + }, + "ids": [ + 0, + 1, + 2 + ] + }, + "filter": { + "idQueue": [ + 1, + 2, + 3 + ], + "list": { + "0": { + "from": "NOW/HOUR-12HOUR", + "to": "NOW/HOUR%2B1HOUR", + "field": "rs_timestamp", + "type": "time", + "fromDateObj": "2016-12-25T22:46:06.507Z", + "toDateObj": "2016-12-26T10:46:06.507Z", + "mandate": "must", + "active": true, + "alias": "", + "id": 0 + } + }, + "ids": [ + 0 + ] + } + }, + "rows": [ + { + "title": "Query and Time Window", + "height": "50px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "error": "", + "span": 8, + "editable": true, + "type": "timepicker", + "loadingEditor": false, + "status": "Stable", + "mode": "relative", + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "7d", + "30d", + "90d", + "1y", + "5y" + ], + "timespan": "12h", + "timefield": "rs_timestamp", + "timeformat": "", + "refresh": { + "enable": true, + "interval": 60, + "min": 3 + }, + "filter_id": 0, + "spyable": true, + "title": "time frame" + }, + { + "span": 4, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=responseElapsed%3A%5B20000%20TO%20*%5D OR responseElapsed%3A%5B15000%20TO%2019999%5D OR responseElapsed%3A%5B0%20TO%2015000%5D&wt=json&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=user_ipaddress&facet.limit=10&facet.missing=true&f.user_ipaddress.facet.sort=count", + "custom": "" + }, + "mode": "count", + "field": "user_ipaddress", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10, + "sortBy": "count", + "order": "descending", + "style": { + "font-size": "48pt" + }, + "donut": false, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "horizontal", + "chart": "hits", + "counter_pos": "none", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "SSA ï¼ online USERS" + } + ] + }, + { + "title": "WARNING", + "height": "550px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 3, + "editable": true, + "type": "map", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=responseElapsed%3A%5B20000%20TO%20*%5D OR responseElapsed%3A%5B15000%20TO%2019999%5D OR responseElapsed%3A%5B0%20TO%2015000%5D&wt=json&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&rows=0&facet=true&facet.field=ipcode&facet.limit=100", + "custom": "" + }, + "mode": "count", + "field": "ipcode", + "stats_field": "", + "decimal_points": 0, + "map": "china", + "useNames": false, + "colors": [ + "#A0E2E2", + "#265656" + ], + "size": 100, + "exclude": [], + "spyable": true, + "index_limit": 0, + "show_queries": true, + "title": "SSA ï¼ user visit distribution" + }, + { + "span": 6, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=responseElapsed%3A%5B20000%20TO%20*%5D OR responseElapsed%3A%5B15000%20TO%2019999%5D OR responseElapsed%3A%5B0%20TO%2015000%5D&wt=json&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=responseElapsed&facet.limit=10&facet.missing=true&f.responseElapsed.facet.sort=count", + "custom": "" + }, + "mode": "count", + "field": "responseElapsed", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10, + "sortBy": "count", + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": false, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "horizontal", + "chart": "dashboard", + "counter_pos": "none", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "SSA ï¼ Health" + }, + { + "span": 3, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "count", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=responseElapsed%3A%5B20000%20TO%20*%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/HOUR-12HOUR&facet.range.end=NOW/HOUR%2B1HOUR&facet.range.gap=%2B30MINUTE\nq=responseElapsed%3A%5B15000%20TO%2019999%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/HOUR-12HOUR&facet.range.end=NOW/HOUR%2B1HOUR&facet.range.gap=%2B30MINUTE\nq=responseElapsed%3A%5B0%20TO%2015000%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/HOUR-12HOUR&facet.range.end=NOW/HOUR%2B1HOUR&facet.range.gap=%2B30MINUTE\n", + "custom": "&fq =responseElapsed:[0 TO 15000 ]" + }, + "max_rows": 100000, + "value_field": null, + "group_field": null, + "auto_int": false, + "resolution": 100, + "interval": "30m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 3, + "timezone": "browser", + "spyable": false, + "zoomlinks": false, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": false, + "x-axis": false, + "y-axis": true, + "percentage": false, + "interactive": false, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "SSA ï¼ user request" + } + ] + }, + { + "title": "Change", + "height": "80px", + "editable": true, + "collapse": true, + "collapsable": true, + "panels": [ + { + "span": 4, + "editable": true, + "type": "ticker", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=responseElapsed%3A%5B20000%20TO%20*%5D&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-25T22:46:06.507Z&facet.range.end=2016-12-26T10:46:06.507Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=responseElapsed%3A%5B20000%20TO%20*%5D&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-25T21:46:06.507Z&facet.range.end=2016-12-26T09:46:06.507Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=responseElapsed%3A%5B15000%20TO%2019999%5D&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-25T22:46:06.507Z&facet.range.end=2016-12-26T10:46:06.507Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=responseElapsed%3A%5B15000%20TO%2019999%5D&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-25T21:46:06.507Z&facet.range.end=2016-12-26T09:46:06.507Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=responseElapsed%3A%5B0%20TO%2015000%5D&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-25T22:46:06.507Z&facet.range.end=2016-12-26T10:46:06.507Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=responseElapsed%3A%5B0%20TO%2015000%5D&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-25T21:46:06.507Z&facet.range.end=2016-12-26T09:46:06.507Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\n" + }, + "style": { + "font-size": "14pt" + }, + "ago": "1h", + "arrangement": "horizontal", + "spyable": true, + "show_queries": false, + "title": "SSA SYSTEM-Risk chaange(hour)" + }, + { + "span": 4, + "editable": true, + "type": "ticker", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=responseElapsed%3A%5B20000%20TO%20*%5D&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-25T22:46:06.507Z&facet.range.end=2016-12-26T10:46:06.507Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=responseElapsed%3A%5B20000%20TO%20*%5D&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-24T22:46:06.507Z&facet.range.end=2016-12-25T10:46:06.507Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=responseElapsed%3A%5B15000%20TO%2019999%5D&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-25T22:46:06.507Z&facet.range.end=2016-12-26T10:46:06.507Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=responseElapsed%3A%5B15000%20TO%2019999%5D&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-24T22:46:06.507Z&facet.range.end=2016-12-25T10:46:06.507Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=responseElapsed%3A%5B0%20TO%2015000%5D&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-25T22:46:06.507Z&facet.range.end=2016-12-26T10:46:06.507Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=responseElapsed%3A%5B0%20TO%2015000%5D&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-24T22:46:06.507Z&facet.range.end=2016-12-25T10:46:06.507Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\n" + }, + "style": { + "font-size": "14pt" + }, + "ago": "1d", + "arrangement": "horizontal", + "spyable": true, + "show_queries": true, + "title": "SSA SYSTEM-Risk chaange(day)" + }, + { + "span": 4, + "editable": true, + "type": "ticker", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=responseElapsed%3A%5B20000%20TO%20*%5D&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-25T22:46:06.507Z&facet.range.end=2016-12-26T10:46:06.507Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=responseElapsed%3A%5B20000%20TO%20*%5D&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-18T22:46:06.507Z&facet.range.end=2016-12-19T10:46:06.507Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=responseElapsed%3A%5B15000%20TO%2019999%5D&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-25T22:46:06.507Z&facet.range.end=2016-12-26T10:46:06.507Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=responseElapsed%3A%5B15000%20TO%2019999%5D&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-18T22:46:06.507Z&facet.range.end=2016-12-19T10:46:06.507Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=responseElapsed%3A%5B0%20TO%2015000%5D&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-25T22:46:06.507Z&facet.range.end=2016-12-26T10:46:06.507Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=responseElapsed%3A%5B0%20TO%2015000%5D&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2016-12-18T22:46:06.507Z&facet.range.end=2016-12-19T10:46:06.507Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\n" + }, + "style": { + "font-size": "14pt" + }, + "ago": "1w", + "arrangement": "horizontal", + "spyable": true, + "show_queries": true, + "title": "SSA SYSTEM-Risk chaange(week)" + } + ] + }, + { + "title": "EVENT COUNT", + "height": "200px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 12, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "count", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=responseElapsed%3A%5B20000%20TO%20*%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/HOUR-12HOUR&facet.range.end=NOW/HOUR%2B1HOUR&facet.range.gap=%2B5MINUTE\nq=responseElapsed%3A%5B15000%20TO%2019999%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/HOUR-12HOUR&facet.range.end=NOW/HOUR%2B1HOUR&facet.range.gap=%2B5MINUTE\nq=responseElapsed%3A%5B0%20TO%2015000%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/HOUR-12HOUR&facet.range.end=NOW/HOUR%2B1HOUR&facet.range.gap=%2B5MINUTE\n", + "custom": "" + }, + "max_rows": 100000, + "value_field": "responseElapsed", + "group_field": null, + "sum_value": false, + "auto_int": true, + "resolution": 100, + "interval": "5m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": true, + "bars": false, + "stack": true, + "points": false, + "lines": true, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": true, + "show_queries": true, + "tooltip": { + "value_type": "individual", + "query_as_alias": false + }, + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "SSAï¼user experience count" + } + ] + }, + { + "title": "response time", + "height": "200px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 6, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "values", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=responseElapsed%3A%5B20000%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp responseElapsed\nq=responseElapsed%3A%5B15000%20TO%2019999%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp responseElapsed\nq=responseElapsed%3A%5B0%20TO%2015000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp responseElapsed\n", + "custom": "&fq=-responseElapsed:[60000 TO *]" + }, + "max_rows": 100000, + "value_field": "responseElapsed", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "5m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "SSAï¼response time(ms)" + }, + { + "span": 6, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "connvalues", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=connectElapsed%3A%5B30000%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp connectElapsed\nq=connectElapsed%3A%5B20000%20TO%2030000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp connectElapsed\nq=connectElapsed%3A%5B0%20TO%2020000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp connectElapsed\n", + "custom": "&fq=-connectElapsed:[40000 TO *]" + }, + "max_rows": 100000, + "value_field": "connectElapsed", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "5m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "SSA ï¼Server connection time(MS)" + } + ] + }, + { + "title": "RESPONSE", + "height": "200px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 6, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "domvalues", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=domElapsed%3A%5B30000%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domElapsed\nq=domElapsed%3A%5B20000%20TO%2030000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domElapsed\nq=domElapsed%3A%5B0%20TO%2020000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domElapsed\n", + "custom": "&fq=-domElapsed:[60000 TO *]" + }, + "max_rows": 100000, + "value_field": "domElapsed", + "group_field": null, + "auto_int": true, + "resolution": 200, + "interval": "5m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 4, + "linewidth": 3, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": false, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "SSAï¼pageload TIME(ms)" + }, + { + "span": 6, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "contvalues", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=domContentLoadedElapsed%3A%5B30000%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domContentLoadedElapsed\nq=domContentLoadedElapsed%3A%5B20000%20TO%2030000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domContentLoadedElapsed\nq=domContentLoadedElapsed%3A%5B0%20TO%2020000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domContentLoadedElapsed\n", + "custom": "" + }, + "max_rows": 100000, + "value_field": "domContentLoadedElapsed", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "5m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 0, + "linewidth": 3, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "SSAï¼content TIME(ms)" + } + ] + }, + { + "title": "time", + "height": "200px", + "editable": true, + "collapse": true, + "collapsable": true, + "panels": [] + }, + { + "title": "Message", + "height": "190px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 4, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "cpuvalues", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=cpu%3A%5B80%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp cpu\nq=cpu%3A%5B60%20TO%2080%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp cpu\nq=cpu%3A%5B0%20TO%2060%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp cpu\n", + "custom": "" + }, + "max_rows": 100000, + "value_field": "cpu", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "5m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": false, + "stack": true, + "points": false, + "lines": true, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "SSAï¼CPU usage(%)" + }, + { + "span": 4, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "mevalues", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=UsedMemery%3A%5B2000%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp UsedMemery\nq=UsedMemery%3A%5B1500%20TO%202000%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp UsedMemery\nq=UsedMemery%3A%5B0%20TO%201500%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp UsedMemery\n", + "custom": "" + }, + "max_rows": 100000, + "value_field": "UsedMemery", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "5m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": false, + "stack": true, + "points": false, + "lines": true, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": false, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "SSAï¼memory usage(MB)" + }, + { + "span": 4, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "diskvalues", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=FreeDiskSpace%3A%5B0%20TO%205%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp FreeDiskSpace\nq=FreeDiskSpace%3A%5B5%20TO%2020%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp FreeDiskSpace\nq=FreeDiskSpace%3A%5B5%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp FreeDiskSpace\n", + "custom": "" + }, + "max_rows": 100000, + "value_field": "FreeDiskSpace", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "5m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": false, + "stack": true, + "points": false, + "lines": true, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "SSAï¼Free disk(GB)" + } + ] + }, + { + "title": "context time", + "height": "200px", + "editable": true, + "collapse": true, + "collapsable": true, + "panels": [] + }, + { + "title": "PIE", + "height": "250px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 3, + "editable": true, + "type": "tagcloud", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=responseElapsed%3A%5B20000%20TO%20*%5D OR responseElapsed%3A%5B15000%20TO%2019999%5D OR responseElapsed%3A%5B0%20TO%2015000%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=br_name&facet.limit=10", + "custom": "" + }, + "field": "br_name", + "size": 10, + "alignment": "horizontal", + "fontScale": 4, + "ignoreStopWords": false, + "spyable": true, + "show_queries": true, + "title": "SSA - user browser" + }, + { + "span": 3, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=responseElapsed%3A%5B20000%20TO%20*%5D OR responseElapsed%3A%5B15000%20TO%2019999%5D OR responseElapsed%3A%5B0%20TO%2015000%5D&wt=json&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=dvce_type&facet.limit=10&facet.missing=true&f.dvce_type.facet.sort=index", + "custom": "" + }, + "mode": "count", + "field": "dvce_type", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10, + "sortBy": "index", + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": true, + "tilt": false, + "labels": false, + "logAxis": false, + "arrangement": "horizontal", + "chart": "pie", + "counter_pos": "above", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#104E8B", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "SSA ï¼User device" + }, + { + "span": 3, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=responseElapsed%3A%5B20000%20TO%20*%5D OR responseElapsed%3A%5B15000%20TO%2019999%5D OR responseElapsed%3A%5B0%20TO%2015000%5D&wt=json&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=os_name&facet.limit=10&facet.missing=true&f.os_name.facet.sort=count", + "custom": "" + }, + "mode": "count", + "field": "os_name", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10, + "sortBy": "count", + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": false, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "horizontal", + "chart": "pie", + "counter_pos": "above", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#104E8B", + "#65C5DB", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "SSA SYSTEM-USER os" + }, + { + "span": 3, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=responseElapsed%3A%5B20000%20TO%20*%5D OR responseElapsed%3A%5B15000%20TO%2019999%5D OR responseElapsed%3A%5B0%20TO%2015000%5D&wt=json&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=user_ipaddress&facet.limit=10&facet.missing=true&f.user_ipaddress.facet.sort=count", + "custom": "" + }, + "mode": "count", + "field": "user_ipaddress", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10, + "sortBy": "count", + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": false, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "horizontal", + "chart": "ebar", + "counter_pos": "above", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "SSA SYSTEM-USER IP top5" + } + ] + }, + { + "title": "Detail", + "height": "150px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 12, + "editable": true, + "type": "fullTextSearch", + "loadingEditor": false, + "status": "Stable", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=responseElapsed%3A%5B20000%20TO%20*%5D OR responseElapsed%3A%5B15000%20TO%2019999%5D OR responseElapsed%3A%5B0%20TO%2015000%5D&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=os_name&facet.field=useragent&facet.field=page_url&facet.field=br_name&facet.field=UsedMemery&facet.field=user_ipaddress&facet.field=dvce_type&wt=json&rows=1500&hl=true&hl.fl=useragent", + "basic_query": "q=responseElapsed%3A%5B20000%20TO%20*%5D OR responseElapsed%3A%5B15000%20TO%2019999%5D OR responseElapsed%3A%5B0%20TO%2015000%5D&fq=rs_timestamp:[NOW/HOUR-12HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=os_name&facet.field=useragent&facet.field=page_url&facet.field=br_name&facet.field=UsedMemery&facet.field=user_ipaddress&facet.field=dvce_type", + "custom": "" + }, + "size": 5, + "pages": 300, + "offset": 0, + "group": "default", + "sort": [ + "os_family" + ], + "style": { + "font-size": "12pt" + }, + "overflow": "min-height", + "fields": [ + "os_name", + "useragent", + "page_url", + "br_name", + "UsedMemery", + "user_ipaddress", + "dvce_type" + ], + "highlight": [], + "sortable": false, + "header": true, + "paging": true, + "field_list": true, + "trimFactor": 200, + "normTimes": true, + "spyable": true, + "saveOption": "json", + "exportSize": 1500, + "exportAll": true, + "facet_limit": 10, + "foundResults": true, + "show_queries": true, + "title": "SSA SYSTEM-Event detail", + "header_field": "app_id", + "body_field": "useragent", + "url_field": "page_url" + } + ] + } + ], + "editable": true, + "index": { + "interval": "none", + "pattern": "[logstash-]YYYY.MM.DD", + "default": "_all" + }, + "style": "dark", + "failover": false, + "panel_hints": true, + "loader": { + "save_gist": false, + "save_elasticsearch": true, + "save_local": true, + "save_default": true, + "save_temp": true, + "save_temp_ttl_enable": true, + "save_temp_ttl": "30d", + "load_gist": true, + "load_elasticsearch": true, + "load_elasticsearch_size": 20, + "load_local": true, + "hide": false, + "dropdown_collections": false, + "save_as_public": false + }, + "solr": { + "server": "/solr/", + "core_name": "apm", + "core_list": [ + "PHP_logs", + "apm", + "apm2" + ], + "global_params": "" + }, + "username": "guest" +} \ No newline at end of file diff --git a/src/app/dashboards/guided.json b/src/app/dashboards/guided.json old mode 100755 new mode 100644 diff --git a/src/app/dashboards/lucidworks-metrics.json b/src/app/dashboards/lucidworks-metrics.json deleted file mode 100644 index 336d255bc..000000000 --- a/src/app/dashboards/lucidworks-metrics.json +++ /dev/null @@ -1,583 +0,0 @@ -{ - "title": "Fusion Metrics", - "services": { - "query": { - "idQueue": [ - 1 - ], - "list": { - "0": { - "query": "*:*", - "alias": "", - "color": "#7EB26D", - "id": 0, - "pin": false, - "type": "lucene" - } - }, - "ids": [ - 0 - ] - }, - "filter": { - "idQueue": [], - "list": { - "0": { - "from": "NOW/DAY-30DAY", - "to": "NOW/DAY%2B1DAY", - "field": "timestamp_tdt", - "type": "time", - "fromDateObj": "2015-11-04T04:43:51.776Z", - "toDateObj": "2015-12-04T04:43:51.776Z", - "mandate": "must", - "active": true, - "alias": "", - "id": 0 - } - }, - "ids": [ - 0 - ] - } - }, - "rows": [ - { - "title": "Options", - "height": "50px", - "editable": true, - "collapse": false, - "collapsable": true, - "panels": [ - { - "title": "Set time span", - "error": "", - "span": 6, - "editable": true, - "group": [ - "default" - ], - "type": "timepicker", - "mode": "relative", - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d", - "1y", - "5y" - ], - "timespan": "30d", - "timefield": "timestamp_tdt", - "timeformat": "", - "refresh": { - "enable": false, - "interval": 300, - "min": 3 - }, - "filter_id": 0, - "status": "Stable", - "spyable": true - }, - { - "error": false, - "span": 6, - "editable": true, - "type": "query", - "loadingEditor": false, - "query": "*:*", - "pinned": true, - "history": [ - "*:*", - "query_s:ipad*", - "query_s:ipad", - "params_name_s:HP* AND params_name_s:*TouchPad*", - "params_name_s:*HP*", - "params_name_s:HP*", - "flag_s:aggr", - "doc_id_s:1945531", - "query_s:iPad" - ], - "remember": 10, - "title": "Search", - "spyable": true - } - ] - }, - { - "title": "Graph", - "height": "350px", - "editable": true, - "collapse": false, - "collapsable": true, - "panels": [ - { - "span": 4, - "editable": true, - "type": "histogram", - "loadingEditor": false, - "mode": "values", - "time_field": "timestamp_dt", - "queries": { - "mode": "all", - "ids": [ - 0 - ], - "query": "q=*%3A*&wt=json&rows=100000&fq=timestamp_tdt:[NOW/DAY-30DAY%20TO%20NOW/DAY%2B1DAY]&fl=timestamp_tdt mean_d\n", - "custom": "&fq=name_s:mem.heap.usage" - }, - "max_rows": 100000, - "value_field": "mean_d", - "group_field": "", - "auto_int": true, - "resolution": 100, - "interval": "12h", - "intervals": [ - "auto", - "1s", - "1m", - "5m", - "10m", - "30m", - "1h", - "3h", - "12h", - "1d", - "1w", - "1M", - "1y" - ], - "fill": 0, - "linewidth": 3, - "timezone": "browser", - "spyable": true, - "zoomlinks": true, - "bars": false, - "stack": false, - "points": false, - "lines": true, - "lines_smooth": true, - "legend": true, - "x-axis": true, - "y-axis": true, - "percentage": false, - "interactive": true, - "options": true, - "tooltip": { - "value_type": "cumulative", - "query_as_alias": true - }, - "title": "Heap Memory usage (percentage)", - "show_queries": true, - "refresh": { - "enable": false, - "interval": 2 - } - }, - { - "span": 4, - "editable": true, - "type": "histogram", - "loadingEditor": false, - "mode": "values", - "time_field": "timestamp_dt", - "queries": { - "mode": "all", - "ids": [ - 0 - ], - "query": "q=*%3A*&wt=json&rows=100000&fq=timestamp_tdt:[NOW/DAY-30DAY%20TO%20NOW/DAY%2B1DAY]&fl=timestamp_tdt mean_d\n", - "custom": "&fq=name_s:mem.pools.PS-Eden-Space.usage" - }, - "max_rows": 100000, - "value_field": "mean_d", - "group_field": "", - "auto_int": true, - "resolution": 100, - "interval": "12h", - "intervals": [ - "auto", - "1s", - "1m", - "5m", - "10m", - "30m", - "1h", - "3h", - "12h", - "1d", - "1w", - "1M", - "1y" - ], - "fill": 0, - "linewidth": 3, - "timezone": "browser", - "spyable": true, - "zoomlinks": true, - "bars": false, - "stack": false, - "points": false, - "lines": true, - "lines_smooth": true, - "legend": true, - "x-axis": true, - "y-axis": true, - "percentage": false, - "interactive": true, - "options": true, - "tooltip": { - "value_type": "cumulative", - "query_as_alias": true - }, - "title": "PS-Eden-Space.usage", - "show_queries": true, - "refresh": { - "enable": false, - "interval": 2 - } - }, - { - "span": 4, - "editable": true, - "type": "histogram", - "loadingEditor": false, - "mode": "values", - "time_field": "timestamp_dt", - "queries": { - "mode": "all", - "ids": [ - 0 - ], - "query": "q=*%3A*&wt=json&rows=100000&fq=timestamp_tdt:[NOW/DAY-30DAY%20TO%20NOW/DAY%2B1DAY]&fl=timestamp_tdt mean_d\n", - "custom": "&fq=name_s:mem.pools.PS-Old-Gen.usage" - }, - "max_rows": 100000, - "value_field": "mean_d", - "group_field": "", - "auto_int": true, - "resolution": 100, - "interval": "12h", - "intervals": [ - "auto", - "1s", - "1m", - "5m", - "10m", - "30m", - "1h", - "3h", - "12h", - "1d", - "1w", - "1M", - "1y" - ], - "fill": 0, - "linewidth": 3, - "timezone": "browser", - "spyable": true, - "zoomlinks": true, - "bars": false, - "stack": true, - "points": false, - "lines": true, - "lines_smooth": true, - "legend": true, - "x-axis": true, - "y-axis": true, - "percentage": false, - "interactive": true, - "options": true, - "tooltip": { - "value_type": "cumulative", - "query_as_alias": false - }, - "title": "mem.pools.PS-Old-Gen.usage", - "show_queries": true, - "refresh": { - "enable": false, - "interval": 2 - } - } - ] - }, - { - "title": "Description", - "height": "150px", - "editable": true, - "collapse": false, - "collapsable": true, - "panels": [ - { - "error": false, - "span": 3, - "editable": true, - "type": "filtering", - "loadingEditor": false, - "title": "Filtering Panel", - "spyable": true - }, - { - "span": 2, - "editable": true, - "type": "terms", - "loadingEditor": false, - "queries": { - "mode": "all", - "ids": [ - 0 - ], - "query": "q=*%3A*&wt=json&rows=0&fq=timestamp_tdt:[NOW/DAY-30DAY%20TO%20NOW/DAY%2B1DAY]&facet=true&facet.field=server_s&facet.limit=10&facet.missing=true", - "custom": "" - }, - "field": "server_s", - "exclude": [], - "missing": false, - "other": false, - "size": 10, - "order": "count", - "style": { - "font-size": "10pt" - }, - "donut": false, - "tilt": false, - "labels": true, - "arrangement": "horizontal", - "chart": "bar", - "counter_pos": "none", - "spyable": true, - "time_field": "timestamp_dt", - "title": "Apollo hostname", - "mode": "count", - "stats_field": "value_d", - "decimal_points": 0, - "logAxis": false, - "lastColor": "", - "show_queries": true, - "chartColors": [ - "#7EB26D", - "#EAB839", - "#6ED0E0", - "#EF843C", - "#E24D42", - "#1F78C1", - "#BA43A9", - "#705DA0", - "#508642", - "#CCA300", - "#447EBC", - "#C15C17", - "#890F02", - "#0A437C", - "#6D1F62", - "#584477", - "#B7DBAB", - "#F4D598", - "#70DBED", - "#F9BA8F", - "#F29191", - "#82B5D8", - "#E5A8E2", - "#AEA2E0", - "#629E51", - "#E5AC0E", - "#64B0C8", - "#E0752D", - "#BF1B00", - "#0A50A1", - "#962D82", - "#614D93", - "#9AC48A", - "#F2C96D", - "#65C5DB", - "#F9934E", - "#EA6460", - "#5195CE", - "#D683CE", - "#806EB7", - "#3F6833", - "#967302", - "#2F575E", - "#99440A", - "#58140C", - "#052B51", - "#511749", - "#3F2B5B", - "#E0F9D7", - "#FCEACA", - "#CFFAFF", - "#F9E2D2", - "#FCE2DE", - "#BADFF4", - "#F9D9F9", - "#DEDAF7" - ], - "refresh": { - "enable": false, - "interval": 2 - } - }, - { - "span": 3, - "editable": true, - "type": "histogram", - "loadingEditor": false, - "mode": "values", - "time_field": "timestamp_dt", - "queries": { - "mode": "all", - "ids": [ - 0 - ], - "query": "q=*%3A*&wt=json&rows=100000&fq=timestamp_tdt:[NOW/DAY-30DAY%20TO%20NOW/DAY%2B1DAY]&fl=timestamp_tdt mean_d\n", - "custom": "&fq=name_s:mem.pools.PS-Perm-Gen.usage" - }, - "max_rows": 100000, - "value_field": "mean_d", - "group_field": null, - "auto_int": true, - "resolution": 100, - "interval": "12h", - "intervals": [ - "auto", - "1s", - "1m", - "5m", - "10m", - "30m", - "1h", - "3h", - "12h", - "1d", - "1w", - "1M", - "1y" - ], - "fill": 0, - "linewidth": 3, - "timezone": "browser", - "spyable": true, - "zoomlinks": true, - "bars": false, - "stack": true, - "points": false, - "lines": true, - "lines_smooth": false, - "legend": true, - "x-axis": true, - "y-axis": true, - "percentage": false, - "interactive": true, - "options": true, - "tooltip": { - "value_type": "cumulative", - "query_as_alias": false - }, - "title": "mem.pools.PS-Perm-Gen.usage", - "show_queries": true, - "refresh": { - "enable": false, - "interval": 2 - } - }, - { - "span": 4, - "editable": true, - "type": "histogram", - "loadingEditor": false, - "mode": "values", - "time_field": "timestamp_dt", - "queries": { - "mode": "all", - "ids": [ - 0 - ], - "query": "q=*%3A*&wt=json&rows=100000&fq=timestamp_tdt:[NOW/DAY-30DAY%20TO%20NOW/DAY%2B1DAY]&fl=timestamp_tdt value_d\n", - "custom": "&fq=name_s:mem.pools.Code-Cache.usage" - }, - "max_rows": 100000, - "value_field": "value_d", - "group_field": null, - "auto_int": true, - "resolution": 100, - "interval": "12h", - "intervals": [ - "auto", - "1s", - "1m", - "5m", - "10m", - "30m", - "1h", - "3h", - "12h", - "1d", - "1w", - "1M", - "1y" - ], - "fill": 0, - "linewidth": 3, - "timezone": "browser", - "spyable": true, - "zoomlinks": true, - "bars": false, - "stack": true, - "points": false, - "lines": true, - "lines_smooth": false, - "legend": true, - "x-axis": true, - "y-axis": true, - "percentage": false, - "interactive": true, - "options": true, - "tooltip": { - "value_type": "cumulative", - "query_as_alias": false - }, - "title": "mem.pools.Code-Cache.usage", - "show_queries": true, - "refresh": { - "enable": false, - "interval": 2 - } - } - ] - } - ], - "editable": true, - "failover": false, - "index": { - "interval": "none", - "pattern": "[logstash-]YYYY.MM.DD", - "default": "NO_TIME_FILTER_OR_INDEX_PATTERN_NOT_MATCHED" - }, - "style": "light", - "panel_hints": true, - "loader": { - "save_gist": false, - "save_elasticsearch": true, - "save_local": true, - "save_default": true, - "save_temp": true, - "save_temp_ttl_enable": true, - "save_temp_ttl": "30d", - "load_gist": true, - "load_elasticsearch": true, - "load_elasticsearch_size": 20, - "load_local": true, - "hide": false, - "dropdown_collections": false - }, - "solr": { - "server": "/api/apollo/query-pipelines/_system/collections/", - "core_name": "system_metrics", - "core_list": [] - } -} diff --git a/src/app/dashboards/lucidworks-searchanalytics.json b/src/app/dashboards/lucidworks-searchanalytics.json deleted file mode 100644 index f8d31ba6e..000000000 --- a/src/app/dashboards/lucidworks-searchanalytics.json +++ /dev/null @@ -1,1135 +0,0 @@ -{ - "title": "Search Analytics", - "services": { - "query": { - "idQueue": [ - 1, - 2, - 3, - 4 - ], - "list": { - "0": { - "query": "*:*", - "alias": "", - "color": "#7EB26D", - "id": 0, - "pin": false, - "type": "lucene" - } - }, - "ids": [ - 0 - ] - }, - "filter": { - "idQueue": [ - 1, - 2 - ], - "list": { - "0": { - "from": "NOW/DAY-30DAY", - "to": "NOW/DAY%2B1DAY", - "field": "timestamp_tdt", - "type": "time", - "fromDateObj": "2014-10-11T15:04:43.319Z", - "toDateObj": "2014-11-10T16:04:43.320Z", - "mandate": "must", - "active": true, - "alias": "", - "id": 0 - } - }, - "ids": [ - 0 - ] - } - }, - "rows": [ - { - "title": "Guide", - "height": "100px", - "editable": true, - "collapse": false, - "collapsable": true, - "panels": [ - { - "error": false, - "span": 12, - "editable": true, - "type": "text", - "loadingEditor": false, - "status": "Stable", - "mode": "markdown", - "content": "In order for the search analytics dashboard to display your data correctly, you will have to select a collection that contains search logs. For example, if you have a collection named, *web*, and you want to look at its search analytics information, then you need to choose *web_logs* collection by using the collection drop-down box on top of this page or configure it under Solr tab in Dashboard Settings. We have initially selected the *default_logs* collection for you, corresponding with the *default* collection that ships with Fusion.", - "style": {}, - "title": "Guide" - } - ] - }, - { - "title": "Query and Time Window", - "height": "50px", - "editable": true, - "collapse": false, - "collapsable": true, - "panels": [ - { - "error": "", - "span": 5, - "editable": true, - "type": "timepicker", - "loadingEditor": false, - "status": "Stable", - "mode": "relative", - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "7d", - "30d", - "90d", - "1y", - "5y" - ], - "timespan": "30d", - "timefield": "timestamp_tdt", - "timeformat": "", - "refresh": { - "enable": false, - "interval": 30, - "min": 3 - }, - "filter_id": 0, - "spyable": true, - "title": "Time Window" - }, - { - "error": false, - "span": 4, - "editable": true, - "group": [ - "default" - ], - "type": "query", - "label": "Search", - "history": [ - "*:*" - ], - "remember": 10, - "pinned": true, - "query": "*:*", - "title": "Search", - "spyable": true, - "def_type": "" - }, - { - "span": 3, - "editable": true, - "type": "hits", - "loadingEditor": false, - "queries": { - "mode": "all", - "ids": [ - 0 - ], - "query": "q=*%3A*&df=q_txt&fq=timestamp_tdt:[NOW/DAY-30DAY%20TO%20NOW/DAY%2B1DAY]&wt=json&rows=0", - "basic_query": "", - "custom": "" - }, - "style": { - "font-size": "14pt" - }, - "arrangement": "horizontal", - "chart": "total", - "counter_pos": "above", - "donut": false, - "tilt": false, - "labels": true, - "spyable": true, - "title": "Total Hits", - "show_queries": true, - "metrics": [ - { - "type": "count", - "field": "id", - "decimalDigits": 0, - "label": "", - "value": "0" - } - ], - "refresh": { - "enable": false, - "interval": 2 - } - } - ] - }, - { - "title": "Filters", - "height": "200px", - "editable": true, - "collapse": false, - "collapsable": true, - "panels": [ - { - "error": false, - "span": 6, - "editable": true, - "spyable": true, - "group": [ - "default" - ], - "type": "filtering" - }, - { - "error": false, - "span": 6, - "editable": true, - "type": "terms", - "loadingEditor": false, - "queries": { - "mode": "all", - "ids": [ - 0 - ], - "query": "q=*%3A*&df=q_txt&wt=json&rows=0&fq=timestamp_tdt:[NOW/DAY-30DAY%20TO%20NOW/DAY%2B1DAY]&facet=true&facet.field=q_s&facet.limit=10", - "custom": "" - }, - "mode": "count", - "field": "q_s", - "stats_field": "", - "decimal_points": 0, - "exclude": [], - "missing": false, - "other": false, - "size": 10, - "order": "descending", - "style": { - "font-size": "10pt" - }, - "donut": false, - "tilt": false, - "labels": true, - "arrangement": "horizontal", - "chart": "bar", - "counter_pos": "above", - "lastColor": "", - "spyable": true, - "chartColors": [ - "#7EB26D", - "#EAB839", - "#6ED0E0", - "#EF843C", - "#E24D42", - "#1F78C1", - "#BA43A9", - "#705DA0", - "#508642", - "#CCA300", - "#447EBC", - "#C15C17", - "#890F02", - "#0A437C", - "#6D1F62", - "#584477", - "#B7DBAB", - "#F4D598", - "#70DBED", - "#F9BA8F", - "#F29191", - "#82B5D8", - "#E5A8E2", - "#AEA2E0", - "#629E51", - "#E5AC0E", - "#64B0C8", - "#E0752D", - "#BF1B00", - "#0A50A1", - "#962D82", - "#614D93", - "#9AC48A", - "#F2C96D", - "#65C5DB", - "#F9934E", - "#EA6460", - "#5195CE", - "#D683CE", - "#806EB7", - "#3F6833", - "#967302", - "#2F575E", - "#99440A", - "#58140C", - "#052B51", - "#511749", - "#3F2B5B", - "#E0F9D7", - "#FCEACA", - "#CFFAFF", - "#F9E2D2", - "#FCE2DE", - "#BADFF4", - "#F9D9F9", - "#DEDAF7" - ], - "title": "Top 10 Searches", - "show_queries": true - } - ] - }, - { - "title": "Graph", - "height": "200px", - "editable": true, - "collapse": false, - "collapsable": true, - "panels": [ - { - "span": 6, - "editable": true, - "type": "histogram", - "loadingEditor": false, - "mode": "count", - "time_field": "timestamp_tdt", - "queries": { - "mode": "all", - "ids": [ - 0 - ], - "query": "q=*%3A*&df=q_txt&wt=json&rows=0&fq=timestamp_tdt:[NOW/DAY-30DAY%20TO%20NOW/DAY%2B1DAY]&facet=true&facet.range=timestamp_tdt&facet.range.start=NOW/DAY-30DAY&facet.range.end=NOW/DAY%2B1DAY&facet.range.gap=%2B12HOUR", - "custom": "" - }, - "max_rows": 100000, - "value_field": null, - "group_field": null, - "auto_int": true, - "resolution": 100, - "interval": "12h", - "intervals": [ - "auto", - "1s", - "1m", - "5m", - "10m", - "30m", - "1h", - "3h", - "12h", - "1d", - "1w", - "1M", - "1y" - ], - "fill": 0, - "linewidth": 3, - "timezone": "browser", - "spyable": true, - "zoomlinks": true, - "bars": true, - "stack": true, - "points": false, - "lines": false, - "legend": true, - "x-axis": true, - "y-axis": true, - "percentage": false, - "interactive": true, - "options": true, - "tooltip": { - "value_type": "cumulative", - "query_as_alias": false - }, - "title": "Event Counts", - "lines_smooth": false - }, - { - "error": false, - "span": 6, - "editable": true, - "type": "terms", - "loadingEditor": false, - "queries": { - "mode": "all", - "ids": [ - 0 - ], - "query": "q=*%3A*&df=q_txt&wt=json&rows=0&fq=timestamp_tdt:[NOW/DAY-30DAY%20TO%20NOW/DAY%2B1DAY]&facet=true&facet.field=q_s&facet.limit=10", - "custom": "&fq=numdocs_l:0" - }, - "mode": "count", - "field": "q_s", - "stats_field": "", - "decimal_points": 0, - "exclude": [], - "missing": false, - "other": false, - "size": 10, - "order": "descending", - "style": { - "font-size": "10pt" - }, - "donut": false, - "tilt": false, - "labels": true, - "arrangement": "horizontal", - "chart": "bar", - "counter_pos": "above", - "lastColor": "", - "spyable": true, - "chartColors": [ - "#7EB26D", - "#EAB839", - "#6ED0E0", - "#EF843C", - "#E24D42", - "#1F78C1", - "#BA43A9", - "#705DA0", - "#508642", - "#CCA300", - "#447EBC", - "#C15C17", - "#890F02", - "#0A437C", - "#6D1F62", - "#584477", - "#B7DBAB", - "#F4D598", - "#70DBED", - "#F9BA8F", - "#F29191", - "#82B5D8", - "#E5A8E2", - "#AEA2E0", - "#629E51", - "#E5AC0E", - "#64B0C8", - "#E0752D", - "#BF1B00", - "#0A50A1", - "#962D82", - "#614D93", - "#9AC48A", - "#F2C96D", - "#65C5DB", - "#F9934E", - "#EA6460", - "#5195CE", - "#D683CE", - "#806EB7", - "#3F6833", - "#967302", - "#2F575E", - "#99440A", - "#58140C", - "#052B51", - "#511749", - "#3F2B5B", - "#E0F9D7", - "#FCEACA", - "#CFFAFF", - "#F9E2D2", - "#FCE2DE", - "#BADFF4", - "#F9D9F9", - "#DEDAF7" - ], - "title": "Top 10 Searches with Zero Result", - "show_queries": true - } - ] - }, - { - "title": "Query Time", - "height": "200px", - "editable": true, - "collapse": false, - "collapsable": true, - "panels": [ - { - "error": false, - "span": 4, - "editable": true, - "type": "terms", - "loadingEditor": false, - "queries": { - "mode": "all", - "ids": [ - 0 - ], - "query": "q=*%3A*&df=q_txt&wt=json&rows=0&fq=timestamp_tdt:[NOW/DAY-30DAY%20TO%20NOW/DAY%2B1DAY]&stats=true&stats.facet=q_s&stats.field=qtime_l", - "custom": "" - }, - "mode": "mean", - "field": "q_s", - "stats_field": "qtime_l", - "decimal_points": 2, - "exclude": [], - "missing": false, - "other": false, - "size": 10, - "order": "descending", - "style": { - "font-size": "10pt" - }, - "donut": false, - "tilt": false, - "labels": true, - "arrangement": "horizontal", - "chart": "bar", - "counter_pos": "above", - "lastColor": "", - "spyable": true, - "chartColors": [ - "#7EB26D", - "#EAB839", - "#6ED0E0", - "#EF843C", - "#E24D42", - "#1F78C1", - "#BA43A9", - "#705DA0", - "#508642", - "#CCA300", - "#447EBC", - "#C15C17", - "#890F02", - "#0A437C", - "#6D1F62", - "#584477", - "#B7DBAB", - "#F4D598", - "#70DBED", - "#F9BA8F", - "#F29191", - "#82B5D8", - "#E5A8E2", - "#AEA2E0", - "#629E51", - "#E5AC0E", - "#64B0C8", - "#E0752D", - "#BF1B00", - "#0A50A1", - "#962D82", - "#614D93", - "#9AC48A", - "#F2C96D", - "#65C5DB", - "#F9934E", - "#EA6460", - "#5195CE", - "#D683CE", - "#806EB7", - "#3F6833", - "#967302", - "#2F575E", - "#99440A", - "#58140C", - "#052B51", - "#511749", - "#3F2B5B", - "#E0F9D7", - "#FCEACA", - "#CFFAFF", - "#F9E2D2", - "#FCE2DE", - "#BADFF4", - "#F9D9F9", - "#DEDAF7" - ], - "title": "Avg Query Time by Search Terms", - "show_queries": true - }, - { - "error": false, - "span": 4, - "editable": true, - "type": "terms", - "loadingEditor": false, - "queries": { - "mode": "all", - "ids": [ - 0 - ], - "query": "q=*%3A*&df=q_txt&wt=json&rows=0&fq=timestamp_tdt:[NOW/DAY-30DAY%20TO%20NOW/DAY%2B1DAY]&stats=true&stats.facet=q_s&stats.field=qtime_l", - "custom": "" - }, - "mode": "min", - "field": "q_s", - "stats_field": "qtime_l", - "decimal_points": 2, - "exclude": [], - "missing": false, - "other": false, - "size": 10, - "order": "descending", - "style": { - "font-size": "10pt" - }, - "donut": false, - "tilt": false, - "labels": true, - "arrangement": "horizontal", - "chart": "bar", - "counter_pos": "above", - "lastColor": "", - "spyable": true, - "chartColors": [ - "#7EB26D", - "#EAB839", - "#6ED0E0", - "#EF843C", - "#E24D42", - "#1F78C1", - "#BA43A9", - "#705DA0", - "#508642", - "#CCA300", - "#447EBC", - "#C15C17", - "#890F02", - "#0A437C", - "#6D1F62", - "#584477", - "#B7DBAB", - "#F4D598", - "#70DBED", - "#F9BA8F", - "#F29191", - "#82B5D8", - "#E5A8E2", - "#AEA2E0", - "#629E51", - "#E5AC0E", - "#64B0C8", - "#E0752D", - "#BF1B00", - "#0A50A1", - "#962D82", - "#614D93", - "#9AC48A", - "#F2C96D", - "#65C5DB", - "#F9934E", - "#EA6460", - "#5195CE", - "#D683CE", - "#806EB7", - "#3F6833", - "#967302", - "#2F575E", - "#99440A", - "#58140C", - "#052B51", - "#511749", - "#3F2B5B", - "#E0F9D7", - "#FCEACA", - "#CFFAFF", - "#F9E2D2", - "#FCE2DE", - "#BADFF4", - "#F9D9F9", - "#DEDAF7" - ], - "title": "Min Query Time by Search Terms", - "show_queries": true - }, - { - "error": false, - "span": 4, - "editable": true, - "type": "terms", - "loadingEditor": false, - "queries": { - "mode": "all", - "ids": [ - 0 - ], - "query": "q=*%3A*&df=q_txt&wt=json&rows=0&fq=timestamp_tdt:[NOW/DAY-30DAY%20TO%20NOW/DAY%2B1DAY]&stats=true&stats.facet=q_s&stats.field=qtime_l", - "custom": "" - }, - "mode": "max", - "field": "q_s", - "stats_field": "qtime_l", - "decimal_points": 2, - "exclude": [], - "missing": false, - "other": false, - "size": 10, - "order": "descending", - "style": { - "font-size": "10pt" - }, - "donut": false, - "tilt": false, - "labels": true, - "arrangement": "horizontal", - "chart": "bar", - "counter_pos": "above", - "lastColor": "", - "spyable": true, - "chartColors": [ - "#7EB26D", - "#EAB839", - "#6ED0E0", - "#EF843C", - "#E24D42", - "#1F78C1", - "#BA43A9", - "#705DA0", - "#508642", - "#CCA300", - "#447EBC", - "#C15C17", - "#890F02", - "#0A437C", - "#6D1F62", - "#584477", - "#B7DBAB", - "#F4D598", - "#70DBED", - "#F9BA8F", - "#F29191", - "#82B5D8", - "#E5A8E2", - "#AEA2E0", - "#629E51", - "#E5AC0E", - "#64B0C8", - "#E0752D", - "#BF1B00", - "#0A50A1", - "#962D82", - "#614D93", - "#9AC48A", - "#F2C96D", - "#65C5DB", - "#F9934E", - "#EA6460", - "#5195CE", - "#D683CE", - "#806EB7", - "#3F6833", - "#967302", - "#2F575E", - "#99440A", - "#58140C", - "#052B51", - "#511749", - "#3F2B5B", - "#E0F9D7", - "#FCEACA", - "#CFFAFF", - "#F9E2D2", - "#FCE2DE", - "#BADFF4", - "#F9D9F9", - "#DEDAF7" - ], - "title": "Max Query Time by Search Terms", - "show_queries": true - } - ] - }, - { - "title": "Total Time", - "height": "200px", - "editable": true, - "collapse": false, - "collapsable": true, - "panels": [ - { - "error": false, - "span": 4, - "editable": true, - "type": "terms", - "loadingEditor": false, - "queries": { - "mode": "all", - "ids": [ - 0 - ], - "query": "q=*%3A*&df=q_txt&wt=json&rows=0&fq=timestamp_tdt:[NOW/DAY-30DAY%20TO%20NOW/DAY%2B1DAY]&stats=true&stats.facet=q_s&stats.field=totaltime_l", - "custom": "" - }, - "mode": "mean", - "field": "q_s", - "stats_field": "totaltime_l", - "decimal_points": 2, - "exclude": [], - "missing": false, - "other": false, - "size": 10, - "order": "descending", - "style": { - "font-size": "10pt" - }, - "donut": false, - "tilt": false, - "labels": true, - "arrangement": "horizontal", - "chart": "bar", - "counter_pos": "above", - "lastColor": "", - "spyable": true, - "chartColors": [ - "#7EB26D", - "#EAB839", - "#6ED0E0", - "#EF843C", - "#E24D42", - "#1F78C1", - "#BA43A9", - "#705DA0", - "#508642", - "#CCA300", - "#447EBC", - "#C15C17", - "#890F02", - "#0A437C", - "#6D1F62", - "#584477", - "#B7DBAB", - "#F4D598", - "#70DBED", - "#F9BA8F", - "#F29191", - "#82B5D8", - "#E5A8E2", - "#AEA2E0", - "#629E51", - "#E5AC0E", - "#64B0C8", - "#E0752D", - "#BF1B00", - "#0A50A1", - "#962D82", - "#614D93", - "#9AC48A", - "#F2C96D", - "#65C5DB", - "#F9934E", - "#EA6460", - "#5195CE", - "#D683CE", - "#806EB7", - "#3F6833", - "#967302", - "#2F575E", - "#99440A", - "#58140C", - "#052B51", - "#511749", - "#3F2B5B", - "#E0F9D7", - "#FCEACA", - "#CFFAFF", - "#F9E2D2", - "#FCE2DE", - "#BADFF4", - "#F9D9F9", - "#DEDAF7" - ], - "title": "Avg Total Time by Search Terms", - "show_queries": true - }, - { - "error": false, - "span": 4, - "editable": true, - "type": "terms", - "loadingEditor": false, - "queries": { - "mode": "all", - "ids": [ - 0 - ], - "query": "q=*%3A*&df=q_txt&wt=json&rows=0&fq=timestamp_tdt:[NOW/DAY-30DAY%20TO%20NOW/DAY%2B1DAY]&stats=true&stats.facet=q_s&stats.field=totaltime_l", - "custom": "" - }, - "mode": "min", - "field": "q_s", - "stats_field": "totaltime_l", - "decimal_points": 2, - "exclude": [], - "missing": false, - "other": false, - "size": 10, - "order": "descending", - "style": { - "font-size": "10pt" - }, - "donut": false, - "tilt": false, - "labels": true, - "arrangement": "horizontal", - "chart": "bar", - "counter_pos": "above", - "lastColor": "", - "spyable": true, - "chartColors": [ - "#7EB26D", - "#EAB839", - "#6ED0E0", - "#EF843C", - "#E24D42", - "#1F78C1", - "#BA43A9", - "#705DA0", - "#508642", - "#CCA300", - "#447EBC", - "#C15C17", - "#890F02", - "#0A437C", - "#6D1F62", - "#584477", - "#B7DBAB", - "#F4D598", - "#70DBED", - "#F9BA8F", - "#F29191", - "#82B5D8", - "#E5A8E2", - "#AEA2E0", - "#629E51", - "#E5AC0E", - "#64B0C8", - "#E0752D", - "#BF1B00", - "#0A50A1", - "#962D82", - "#614D93", - "#9AC48A", - "#F2C96D", - "#65C5DB", - "#F9934E", - "#EA6460", - "#5195CE", - "#D683CE", - "#806EB7", - "#3F6833", - "#967302", - "#2F575E", - "#99440A", - "#58140C", - "#052B51", - "#511749", - "#3F2B5B", - "#E0F9D7", - "#FCEACA", - "#CFFAFF", - "#F9E2D2", - "#FCE2DE", - "#BADFF4", - "#F9D9F9", - "#DEDAF7" - ], - "title": "Min Total Time by Search Terms", - "show_queries": true - }, - { - "error": false, - "span": 4, - "editable": true, - "type": "terms", - "loadingEditor": false, - "queries": { - "mode": "all", - "ids": [ - 0 - ], - "query": "q=*%3A*&df=q_txt&wt=json&rows=0&fq=timestamp_tdt:[NOW/DAY-30DAY%20TO%20NOW/DAY%2B1DAY]&stats=true&stats.facet=q_s&stats.field=totaltime_l", - "custom": "" - }, - "mode": "max", - "field": "q_s", - "stats_field": "totaltime_l", - "decimal_points": 2, - "exclude": [], - "missing": false, - "other": false, - "size": 10, - "order": "descending", - "style": { - "font-size": "10pt" - }, - "donut": false, - "tilt": false, - "labels": true, - "arrangement": "horizontal", - "chart": "bar", - "counter_pos": "above", - "lastColor": "", - "spyable": true, - "chartColors": [ - "#7EB26D", - "#EAB839", - "#6ED0E0", - "#EF843C", - "#E24D42", - "#1F78C1", - "#BA43A9", - "#705DA0", - "#508642", - "#CCA300", - "#447EBC", - "#C15C17", - "#890F02", - "#0A437C", - "#6D1F62", - "#584477", - "#B7DBAB", - "#F4D598", - "#70DBED", - "#F9BA8F", - "#F29191", - "#82B5D8", - "#E5A8E2", - "#AEA2E0", - "#629E51", - "#E5AC0E", - "#64B0C8", - "#E0752D", - "#BF1B00", - "#0A50A1", - "#962D82", - "#614D93", - "#9AC48A", - "#F2C96D", - "#65C5DB", - "#F9934E", - "#EA6460", - "#5195CE", - "#D683CE", - "#806EB7", - "#3F6833", - "#967302", - "#2F575E", - "#99440A", - "#58140C", - "#052B51", - "#511749", - "#3F2B5B", - "#E0F9D7", - "#FCEACA", - "#CFFAFF", - "#F9E2D2", - "#FCE2DE", - "#BADFF4", - "#F9D9F9", - "#DEDAF7" - ], - "title": "Max Total Time by Search Terms", - "show_queries": true - } - ] - }, - { - "title": "Table", - "height": "150px", - "editable": true, - "collapse": false, - "collapsable": true, - "panels": [ - { - "span": 12, - "editable": true, - "type": "table", - "loadingEditor": false, - "status": "Stable", - "queries": { - "mode": "all", - "ids": [ - 0 - ], - "query": "q=*%3A*&df=q_txt&fq=timestamp_tdt:[NOW/DAY-30DAY%20TO%20NOW/DAY%2B1DAY]&sort=timestamp_tdt desc&wt=json&rows=10000", - "basic_query": "q=*%3A*&df=q_txt&fq=timestamp_tdt:[NOW/DAY-30DAY%20TO%20NOW/DAY%2B1DAY]&sort=timestamp_tdt desc", - "custom": "" - }, - "size": 10, - "pages": 1000, - "offset": 0, - "sort": [ - "timestamp_tdt", - "desc" - ], - "group": "default", - "style": { - "font-size": "9pt" - }, - "overflow": "min-height", - "fields": [ - "timestamp_tdt", - "q_s", - "numdocs_l", - "qtime_l", - "totaltime_l" - ], - "highlight": [], - "sortable": true, - "header": true, - "paging": true, - "field_list": true, - "trimFactor": 300, - "normTimes": true, - "spyable": true, - "saveOption": "json", - "exportSize": 10000, - "exportAll": true, - "displayLinkIcon": true, - "imageFields": [], - "imgFieldWidth": "auto", - "imgFieldHeight": "85px", - "title": "Table panel", - "show_queries": true, - "important_fields": [], - "maxNumCalcTopFields": 20, - "calcTopFieldValuesFromAllData": false, - "refresh": { - "enable": false, - "interval": 2 - } - } - ] - } - ], - "editable": true, - "index": { - "interval": "none", - "pattern": "[logstash-]YYYY.MM.DD", - "default": "_all" - }, - "style": "light", - "failover": false, - "panel_hints": true, - "loader": { - "save_gist": false, - "save_elasticsearch": true, - "save_local": true, - "save_default": true, - "save_temp": true, - "save_temp_ttl_enable": true, - "save_temp_ttl": "30d", - "load_gist": true, - "load_elasticsearch": true, - "load_elasticsearch_size": 20, - "load_local": true, - "hide": false, - "dropdown_collections": true - }, - "solr": { - "server": "/api/apollo/query-pipelines/_system/collections/", - "core_name": "default_logs", - "core_list": [], - "global_params": "&df=q_txt" - } -} diff --git a/src/app/dashboards/lucidworks-signals.json b/src/app/dashboards/lucidworks-signals.json deleted file mode 100644 index 9666b488c..000000000 --- a/src/app/dashboards/lucidworks-signals.json +++ /dev/null @@ -1,824 +0,0 @@ -{ - "title": "Fusion Signals", - "services": { - "query": { - "idQueue": [ - 1 - ], - "list": { - "0": { - "query": "*:*", - "alias": "", - "color": "#7EB26D", - "id": 0, - "pin": false, - "type": "lucene" - } - }, - "ids": [ - 0 - ] - }, - "filter": { - "idQueue": [ - 1, - 2 - ], - "list": { - "0": { - "from": "NOW/DAY-30DAY", - "to": "NOW/DAY%2B1DAY", - "field": "timestamp_tdt", - "type": "time", - "fromDateObj": "2016-04-27T00:05:06.093Z", - "toDateObj": "2016-05-27T00:05:06.093Z", - "mandate": "must", - "active": true, - "alias": "", - "id": 0 - } - }, - "ids": [ - 0 - ] - } - }, - "rows": [ - { - "title": "Options", - "height": "50px", - "editable": true, - "collapse": false, - "collapsable": true, - "panels": [ - { - "title": "Set time span", - "error": "", - "span": 5, - "editable": true, - "group": [ - "default" - ], - "type": "timepicker", - "mode": "relative", - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d", - "1y", - "5y" - ], - "timespan": "30d", - "timefield": "timestamp_tdt", - "timeformat": "", - "refresh": { - "enable": false, - "interval": 600, - "min": 3 - }, - "filter_id": 0, - "status": "Stable", - "spyable": true - }, - { - "error": false, - "span": 3, - "editable": true, - "type": "query", - "loadingEditor": false, - "query": "*:*", - "pinned": true, - "history": [ - "*:*" - ], - "remember": 10, - "title": "Search", - "spyable": true - }, - { - "error": false, - "span": 4, - "editable": true, - "type": "text", - "loadingEditor": false, - "status": "Stable", - "mode": "markdown", - "content": "Lucidworks Fusion ships with a collection named *default*. As such, this dashboard is initially configured to look for a collection named *default_signals*. To change it to use your signals collection, choose the *Configure* option in the upper right corner of the screen (hint: it looks like a gear) and set your collection name to be the name of your collection's signals store. For instance, if you have a collection named *web*, then your signals collection would be named *web_signals*. \n\n*Notes*\n\nYour collection must have the signal capture feature enabled. To turn on signal capture, visit the Admin app, select Collections, then select the collection you wish to enable signals for and toggle the signals option.", - "style": {}, - "title": "Getting Started" - } - ] - }, - { - "title": "Graph", - "height": "350px", - "editable": true, - "collapse": false, - "collapsable": true, - "panels": [ - { - "span": 6, - "editable": true, - "type": "histogram", - "loadingEditor": false, - "mode": "count", - "queries": { - "mode": "all", - "ids": [ - 0 - ], - "query": "q=*%3A*&wt=json&rows=0&fq=timestamp_tdt:[NOW/DAY-30DAY%20TO%20NOW/DAY%2B1DAY]&facet=true&facet.range=timestamp_tdt&facet.range.start=NOW/DAY-30DAY&facet.range.end=NOW/DAY%2B1DAY&facet.range.gap=%2B12HOUR\n", - "custom": "" - }, - "max_rows": 100000, - "value_field": null, - "group_field": null, - "auto_int": true, - "resolution": 100, - "interval": "12h", - "intervals": [ - "auto", - "1s", - "1m", - "5m", - "10m", - "30m", - "1h", - "3h", - "12h", - "1d", - "1w", - "1M", - "1y" - ], - "fill": 0, - "linewidth": 3, - "timezone": "browser", - "spyable": true, - "zoomlinks": true, - "bars": true, - "stack": true, - "points": false, - "lines": false, - "lines_smooth": false, - "legend": true, - "x-axis": true, - "y-axis": true, - "percentage": false, - "interactive": true, - "options": true, - "show_queries": true, - "tooltip": { - "value_type": "cumulative", - "query_as_alias": false - }, - "refresh": { - "enable": false, - "interval": 2 - }, - "title": "Clicks" - }, - { - "span": 6, - "editable": true, - "type": "terms", - "loadingEditor": false, - "queries": { - "mode": "all", - "ids": [ - 0 - ], - "query": "q=*%3A*&wt=json&fq=timestamp_tdt:[NOW/DAY-30DAY%20TO%20NOW/DAY%2B1DAY]&facet=true&facet.field=query_s&facet.limit=20&facet.missing=true&f.query_s.facet.sort=count" - }, - "field": "query_s", - "exclude": [], - "missing": true, - "other": true, - "size": 20, - "order": "count", - "style": { - "font-size": "10pt" - }, - "donut": true, - "tilt": true, - "labels": false, - "arrangement": "horizontal", - "chart": "pie", - "counter_pos": "none", - "spyable": true, - "title": "Queries", - "time_field": "timestamp_tdt", - "mode": "count", - "stats_field": "", - "decimal_points": 0, - "lastColor": "", - "chartColors": [ - "#7EB26D", - "#EAB839", - "#6ED0E0", - "#EF843C", - "#E24D42", - "#1F78C1", - "#BA43A9", - "#705DA0", - "#508642", - "#CCA300", - "#447EBC", - "#C15C17", - "#890F02", - "#0A437C", - "#6D1F62", - "#584477", - "#B7DBAB", - "#F4D598", - "#70DBED", - "#F9BA8F", - "#F29191", - "#82B5D8", - "#E5A8E2", - "#AEA2E0", - "#629E51", - "#E5AC0E", - "#64B0C8", - "#E0752D", - "#BF1B00", - "#0A50A1", - "#962D82", - "#614D93", - "#9AC48A", - "#F2C96D", - "#65C5DB", - "#F9934E", - "#EA6460", - "#5195CE", - "#D683CE", - "#806EB7", - "#3F6833", - "#967302", - "#2F575E", - "#99440A", - "#58140C", - "#052B51", - "#511749", - "#3F2B5B", - "#E0F9D7", - "#FCEACA", - "#CFFAFF", - "#F9E2D2", - "#FCE2DE", - "#BADFF4", - "#F9D9F9", - "#DEDAF7" - ], - "sortBy": "count", - "logAxis": false, - "exportSize": 10000, - "show_queries": true, - "refresh": { - "enable": false, - "interval": 2 - } - } - ] - }, - { - "title": "Description", - "height": "150px", - "editable": true, - "collapse": false, - "collapsable": true, - "panels": [ - { - "span": 3, - "editable": true, - "type": "terms", - "loadingEditor": false, - "queries": { - "mode": "all", - "ids": [ - 0 - ], - "query": "q=*%3A*&wt=json&fq=timestamp_tdt:[NOW/DAY-30DAY%20TO%20NOW/DAY%2B1DAY]&facet=true&facet.field=doc_id_s&facet.limit=10&facet.missing=true&f.doc_id_s.facet.sort=count" - }, - "field": "doc_id_s", - "exclude": [], - "missing": true, - "other": true, - "size": 10, - "order": "count", - "style": { - "font-size": "10pt" - }, - "donut": false, - "tilt": false, - "labels": false, - "arrangement": "horizontal", - "chart": "pie", - "counter_pos": "none", - "spyable": true, - "time_field": "timestamp_tdt", - "title": "Documents", - "mode": "count", - "stats_field": "", - "decimal_points": 0, - "lastColor": "", - "chartColors": [ - "#7EB26D", - "#EAB839", - "#6ED0E0", - "#EF843C", - "#E24D42", - "#1F78C1", - "#BA43A9", - "#705DA0", - "#508642", - "#CCA300", - "#447EBC", - "#C15C17", - "#890F02", - "#0A437C", - "#6D1F62", - "#584477", - "#B7DBAB", - "#F4D598", - "#70DBED", - "#F9BA8F", - "#F29191", - "#82B5D8", - "#E5A8E2", - "#AEA2E0", - "#629E51", - "#E5AC0E", - "#64B0C8", - "#E0752D", - "#BF1B00", - "#0A50A1", - "#962D82", - "#614D93", - "#9AC48A", - "#F2C96D", - "#65C5DB", - "#F9934E", - "#EA6460", - "#5195CE", - "#D683CE", - "#806EB7", - "#3F6833", - "#967302", - "#2F575E", - "#99440A", - "#58140C", - "#052B51", - "#511749", - "#3F2B5B", - "#E0F9D7", - "#FCEACA", - "#CFFAFF", - "#F9E2D2", - "#FCE2DE", - "#BADFF4", - "#F9D9F9", - "#DEDAF7" - ], - "sortBy": "count", - "logAxis": false, - "exportSize": 10000, - "show_queries": true, - "refresh": { - "enable": false, - "interval": 2 - } - }, - { - "span": 3, - "editable": true, - "type": "terms", - "loadingEditor": false, - "queries": { - "mode": "all", - "ids": [ - 0 - ], - "query": "q=*%3A*&wt=json&fq=timestamp_tdt:[NOW/DAY-30DAY%20TO%20NOW/DAY%2B1DAY]&facet=true&facet.field=type_s&facet.limit=10&facet.missing=true&f.type_s.facet.sort=count" - }, - "field": "type_s", - "exclude": [], - "missing": false, - "other": false, - "size": 10, - "order": "count", - "style": { - "font-size": "10pt" - }, - "donut": false, - "tilt": false, - "labels": true, - "arrangement": "horizontal", - "chart": "table", - "counter_pos": "none", - "spyable": true, - "time_field": "timestamp_tdt", - "title": "Type of Event", - "mode": "count", - "stats_field": "", - "decimal_points": 0, - "lastColor": "", - "chartColors": [ - "#7EB26D", - "#EAB839", - "#6ED0E0", - "#EF843C", - "#E24D42", - "#1F78C1", - "#BA43A9", - "#705DA0", - "#508642", - "#CCA300", - "#447EBC", - "#C15C17", - "#890F02", - "#0A437C", - "#6D1F62", - "#584477", - "#B7DBAB", - "#F4D598", - "#70DBED", - "#F9BA8F", - "#F29191", - "#82B5D8", - "#E5A8E2", - "#AEA2E0", - "#629E51", - "#E5AC0E", - "#64B0C8", - "#E0752D", - "#BF1B00", - "#0A50A1", - "#962D82", - "#614D93", - "#9AC48A", - "#F2C96D", - "#65C5DB", - "#F9934E", - "#EA6460", - "#5195CE", - "#D683CE", - "#806EB7", - "#3F6833", - "#967302", - "#2F575E", - "#99440A", - "#58140C", - "#052B51", - "#511749", - "#3F2B5B", - "#E0F9D7", - "#FCEACA", - "#CFFAFF", - "#F9E2D2", - "#FCE2DE", - "#BADFF4", - "#F9D9F9", - "#DEDAF7" - ], - "sortBy": "count", - "logAxis": false, - "exportSize": 10000, - "show_queries": true, - "refresh": { - "enable": false, - "interval": 2 - } - }, - { - "span": 3, - "editable": true, - "type": "terms", - "loadingEditor": false, - "queries": { - "mode": "all", - "ids": [ - 0 - ], - "query": "q=*%3A*&wt=json&fq=timestamp_tdt:[NOW/DAY-30DAY%20TO%20NOW/DAY%2B1DAY]&facet=true&facet.field=flag_s&facet.limit=10&facet.missing=true&f.flag_s.facet.sort=count" - }, - "field": "flag_s", - "exclude": [], - "missing": true, - "other": true, - "size": 10, - "order": "count", - "style": { - "font-size": "10pt" - }, - "donut": false, - "tilt": false, - "labels": true, - "arrangement": "horizontal", - "chart": "pie", - "counter_pos": "none", - "spyable": true, - "time_field": "timestamp_tdt", - "title": "Flag", - "mode": "count", - "stats_field": "", - "decimal_points": 0, - "lastColor": "", - "chartColors": [ - "#7EB26D", - "#EAB839", - "#6ED0E0", - "#EF843C", - "#E24D42", - "#1F78C1", - "#BA43A9", - "#705DA0", - "#508642", - "#CCA300", - "#447EBC", - "#C15C17", - "#890F02", - "#0A437C", - "#6D1F62", - "#584477", - "#B7DBAB", - "#F4D598", - "#70DBED", - "#F9BA8F", - "#F29191", - "#82B5D8", - "#E5A8E2", - "#AEA2E0", - "#629E51", - "#E5AC0E", - "#64B0C8", - "#E0752D", - "#BF1B00", - "#0A50A1", - "#962D82", - "#614D93", - "#9AC48A", - "#F2C96D", - "#65C5DB", - "#F9934E", - "#EA6460", - "#5195CE", - "#D683CE", - "#806EB7", - "#3F6833", - "#967302", - "#2F575E", - "#99440A", - "#58140C", - "#052B51", - "#511749", - "#3F2B5B", - "#E0F9D7", - "#FCEACA", - "#CFFAFF", - "#F9E2D2", - "#FCE2DE", - "#BADFF4", - "#F9D9F9", - "#DEDAF7" - ], - "sortBy": "count", - "logAxis": false, - "exportSize": 10000, - "show_queries": true, - "refresh": { - "enable": false, - "interval": 2 - } - }, - { - "span": 3, - "editable": true, - "type": "terms", - "loadingEditor": false, - "queries": { - "mode": "all", - "ids": [ - 0 - ], - "query": "q=*%3A*&wt=json&fq=timestamp_tdt:[NOW/DAY-30DAY%20TO%20NOW/DAY%2B1DAY]&facet=true&facet.field=count_i&facet.limit=10&facet.missing=true&f.count_i.facet.sort=count" - }, - "field": "count_i", - "exclude": [], - "missing": true, - "other": true, - "size": 10, - "order": "count", - "style": { - "font-size": "10pt" - }, - "donut": false, - "tilt": false, - "labels": true, - "arrangement": "horizontal", - "chart": "pie", - "counter_pos": "none", - "spyable": true, - "time_field": "timestamp_tdt", - "title": "Counts in Event", - "mode": "count", - "stats_field": "", - "decimal_points": 0, - "lastColor": "", - "chartColors": [ - "#7EB26D", - "#EAB839", - "#6ED0E0", - "#EF843C", - "#E24D42", - "#1F78C1", - "#BA43A9", - "#705DA0", - "#508642", - "#CCA300", - "#447EBC", - "#C15C17", - "#890F02", - "#0A437C", - "#6D1F62", - "#584477", - "#B7DBAB", - "#F4D598", - "#70DBED", - "#F9BA8F", - "#F29191", - "#82B5D8", - "#E5A8E2", - "#AEA2E0", - "#629E51", - "#E5AC0E", - "#64B0C8", - "#E0752D", - "#BF1B00", - "#0A50A1", - "#962D82", - "#614D93", - "#9AC48A", - "#F2C96D", - "#65C5DB", - "#F9934E", - "#EA6460", - "#5195CE", - "#D683CE", - "#806EB7", - "#3F6833", - "#967302", - "#2F575E", - "#99440A", - "#58140C", - "#052B51", - "#511749", - "#3F2B5B", - "#E0F9D7", - "#FCEACA", - "#CFFAFF", - "#F9E2D2", - "#FCE2DE", - "#BADFF4", - "#F9D9F9", - "#DEDAF7" - ], - "sortBy": "count", - "logAxis": false, - "exportSize": 10000, - "show_queries": true, - "refresh": { - "enable": false, - "interval": 2 - } - } - ] - }, - { - "title": "Events", - "height": "350px", - "editable": true, - "collapse": false, - "collapsable": true, - "panels": [ - { - "title": "All events", - "span": 12, - "editable": true, - "group": [ - "default" - ], - "type": "table", - "size": 100, - "pages": 10, - "offset": 0, - "sort": [ - "timestamp_tdt", - "desc" - ], - "style": { - "font-size": "9pt" - }, - "overflow": "min-height", - "fields": [ - "query_s", - "doc_id_s", - "type_s", - "count_i", - "flag_s", - "weight_d", - "timestamp_tdt" - ], - "highlight": [], - "sortable": true, - "header": true, - "paging": true, - "spyable": true, - "queries": { - "mode": "all", - "ids": [ - 0 - ], - "query": "q=*%3A*&fq=timestamp_tdt:[NOW/DAY-30DAY%20TO%20NOW/DAY%2B1DAY]&sort=timestamp_tdt desc&wt=json&rows=1000", - "basic_query": "q=*%3A*&fq=timestamp_tdt:[NOW/DAY-30DAY%20TO%20NOW/DAY%2B1DAY]&sort=timestamp_tdt desc" - }, - "field_list": true, - "status": "Stable", - "trimFactor": 300, - "normTimes": true, - "time_field": "timestamp_tdt", - "saveOption": "json", - "exportSize": 1000, - "exportAll": true, - "displayLinkIcon": true, - "imageFields": [], - "imgFieldWidth": "auto", - "imgFieldHeight": "85px", - "important_fields": [], - "show_queries": true, - "maxNumCalcTopFields": 20, - "calcTopFieldValuesFromAllData": false, - "refresh": { - "enable": false, - "interval": 2 - } - } - ] - }, - { - "title": "Filter row", - "height": "150px", - "editable": true, - "collapse": false, - "collapsable": true, - "panels": [ - { - "error": false, - "span": 4, - "editable": true, - "type": "filtering", - "loadingEditor": false, - "title": "Filtering panel", - "spyable": true - } - ] - } - ], - "editable": true, - "failover": false, - "index": { - "interval": "none", - "pattern": "[logstash-]YYYY.MM.DD", - "default": "NO_TIME_FILTER_OR_INDEX_PATTERN_NOT_MATCHED" - }, - "style": "light", - "panel_hints": true, - "loader": { - "save_gist": false, - "save_elasticsearch": true, - "save_local": true, - "save_default": true, - "save_temp": true, - "save_temp_ttl_enable": true, - "save_temp_ttl": "30d", - "load_gist": true, - "load_elasticsearch": true, - "load_elasticsearch_size": 20, - "load_local": true, - "hide": false, - "dropdown_collections": true, - "save_as_public": false - }, - "solr": { - "server": "/api/apollo/query-pipelines/_system/collections/", - "core_name": "default_signals", - "core_list": [] - }, - "username": "admin" -} diff --git a/src/app/dashboards/realsight.apm.2.json b/src/app/dashboards/realsight.apm.2.json new file mode 100644 index 000000000..2019a33fb --- /dev/null +++ b/src/app/dashboards/realsight.apm.2.json @@ -0,0 +1,233 @@ +{ + "title": "RealSight APM (RealTime) 仪表盘 2", + "services": { + "query": { + "idQueue": [ + 1, + 2, + 3, + 4 + ], + "list": { + "0": { + "query": "*:*", + "alias": "", + "color": "#7EB26D", + "id": 0, + "pin": false, + "type": "lucene" + } + }, + "ids": [ + 0 + ] + }, + "filter": { + "idQueue": [ + 1, + 2, + 3, + 4 + ], + "list": { + "0": { + "from": "NOW/MINUTE-15MINUTE", + "to": "NOW/MINUTE%2B1MINUTE", + "field": "rs_timestamp", + "type": "time", + "fromDateObj": "2016-08-27T06:38:31.990Z", + "toDateObj": "2016-08-27T06:53:31.990Z", + "mandate": "must", + "active": true, + "alias": "", + "id": 0 + } + }, + "ids": [ + 0 + ] + } + }, + "rows": [ + { + "title": "Query and Time Window", + "height": "50px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "error": "", + "span": 5, + "editable": true, + "type": "timepicker", + "loadingEditor": false, + "status": "Stable", + "mode": "relative", + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "7d", + "30d", + "90d", + "1y", + "5y" + ], + "timespan": "15m", + "timefield": "rs_timestamp", + "timeformat": "", + "refresh": { + "enable": true, + "interval": 3, + "min": 1 + }, + "filter_id": 0, + "spyable": true, + "title": "Time Window" + }, + { + "error": false, + "span": 3, + "editable": true, + "group": [ + "default" + ], + "type": "query", + "label": "Search", + "history": [ + "*:*" + ], + "remember": 10, + "pinned": true, + "query": "*:*", + "title": "Search", + "spyable": true, + "def_type": "" + } + ] + }, + { + "title": "Filters", + "height": "50px", + "editable": true, + "collapse": true, + "collapsable": true, + "panels": [ + { + "error": false, + "span": 8, + "editable": true, + "spyable": true, + "group": [ + "default" + ], + "type": "filtering" + } + ] + }, + { + "title": "Histogram row", + "height": "150px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 12, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "count", + "time_field": "rs_timestamp", + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-1HOUR%20TO%20NOW/HOUR-1HOUR]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/HOUR-1HOUR&facet.range.end=NOW/HOUR%2B1HOUR&facet.range.gap=%2B30SECOND\n", + "custom": "" + }, + "max_rows": 100000, + "value_field": "polarityCount_i", + "group_field": "polarity_s", + "auto_int": true, + "resolution": 100, + "interval": "10s", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 0, + "linewidth": 3, + "timezone": "browser", + "spyable": true, + "zoomlinks": true, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "Web Visit Count", + "lines_smooth": false, + "show_queries": true + } + ] + } + ], + "editable": true, + "index": { + "interval": "none", + "pattern": "[logstash-]YYYY.MM.DD", + "default": "_all" + }, + "style": "dark", + "failover": false, + "panel_hints": true, + "loader": { + "save_gist": false, + "save_elasticsearch": true, + "save_local": true, + "save_default": true, + "save_temp": true, + "save_temp_ttl_enable": true, + "save_temp_ttl": "30d", + "load_gist": true, + "load_elasticsearch": true, + "load_elasticsearch_size": 20, + "load_local": true, + "hide": false, + "dropdown_collections": false + }, + "solr": { + "server": "/solr/", + "core_name": "apm2", + "core_list": [ + "apm_shard1_replica1" + ], + "global_params": "&df=id" + } +} \ No newline at end of file diff --git a/src/app/dashboards/realsight.apm.3.json b/src/app/dashboards/realsight.apm.3.json new file mode 100644 index 000000000..481cd54bd --- /dev/null +++ b/src/app/dashboards/realsight.apm.3.json @@ -0,0 +1,746 @@ +{ + "title": "RealSight APM (RealTime) 实时状æ€ç›‘控", + "services": { + "query": { + "idQueue": [ + 1, + 2, + 3, + 4 + ], + "list": { + "0": { + "query": "*:*", + "alias": "", + "color": "#7EB26D", + "id": 0, + "pin": false, + "type": "lucene" + } + }, + "ids": [ + 0 + ] + }, + "filter": { + "idQueue": [ + 1, + 2, + 3, + 4 + ], + "list": { + "0": { + "from": "NOW/MINUTE-15MINUTE", + "to": "NOW/MINUTE%2B1MINUTE", + "field": "rs_timestamp", + "type": "time", + "fromDateObj": "2016-08-27T06:38:31.990Z", + "toDateObj": "2016-08-27T06:53:31.990Z", + "mandate": "must", + "active": true, + "alias": "", + "id": 0 + } + }, + "ids": [ + 0 + ] + } + }, + "rows": [ + { + "title": "检索", + "height": "50px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "error": "", + "span": 5, + "editable": true, + "type": "timepicker", + "loadingEditor": false, + "status": "Stable", + "mode": "relative", + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "7d", + "30d", + "90d", + "1y", + "5y" + ], + "timespan": "12h", + "timefield": "rs_timestamp", + "timeformat": "", + "refresh": { + "enable": true, + "interval": 3, + "min": 1 + }, + "filter_id": 0, + "spyable": true, + "title": "时间范围" + }, + { + "error": false, + "span": 3, + "editable": true, + "group": [ + "default" + ], + "type": "query", + "label": "Search", + "history": [ + "*:*" + ], + "remember": 10, + "pinned": true, + "query": "*:*", + "title": "模糊查询", + "spyable": true, + "def_type": "" + }, + { + "span": 4, + "editable": true, + "type": "hits", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&fq=rs_timestamp:[NOW/MINUTE-15MINUTE%20TO%20NOW/MINUTE%2B1MINUTE]&wt=json&rows=0\n", + "basic_query": "", + "custom": "" + }, + "style": { + "font-size": "26pt" + }, + "arrangement": "horizontal", + "chart": "total", + "counter_pos": "above", + "donut": false, + "tilt": false, + "labels": true, + "spyable": true, + "title": "访问总é‡", + "show_queries": true + } + ] + }, + { + "title": "æ¡ä»¶è¿‡æ»¤", + "height": "50px", + "editable": true, + "collapse": true, + "collapsable": true, + "panels": [ + { + "error": false, + "span": 8, + "editable": true, + "spyable": true, + "group": [ + "default" + ], + "type": "filtering" + } + ] + }, + { + "title": "页é¢è®¿é—®çжæ€", + "height": "150px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 12, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "count", + "time_field": "rs_timestamp", + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-1HOUR%20TO%20NOW/HOUR-1HOUR]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/HOUR-1HOUR&facet.range.end=NOW/HOUR%2B1HOUR&facet.range.gap=%2B30SECOND\n", + "custom": "" + }, + "max_rows": 100000, + "value_field": "polarityCount_i", + "group_field": "polarity_s", + "auto_int": true, + "resolution": 100, + "interval": "10s", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 0, + "linewidth": 3, + "timezone": "browser", + "spyable": true, + "zoomlinks": true, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "实时页é¢è®¿é—®", + "lines_smooth": false, + "show_queries": true + } + ] + }, + { + "title": "分æž", + "height": "250px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 2, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=rs_timestamp:[NOW/MINUTE-15MINUTE%20TO%20NOW/MINUTE%2B1MINUTE]&facet=true&facet.field=br_name&facet.limit=10&facet.missing=true", + "custom": "" + }, + "mode": "count", + "field": "br_name", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": true, + "size": 10, + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": true, + "tilt": false, + "labels": true, + "arrangement": "horizontal", + "chart": "pie", + "counter_pos": "none", + "lastColor": "rgb(110,208,224)", + "spyable": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "title": "æµè§ˆå™¨ç±»åž‹", + "logAxis": false, + "show_queries": true + }, + { + "span": 2, + "editable": true, + "type": "tagcloud", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=rs_timestamp:[NOW/MINUTE-15MINUTE%20TO%20NOW/MINUTE%2B1MINUTE]&facet=true&facet.field=user_ipaddress&facet.limit=20", + "custom": "" + }, + "field": "user_ipaddress", + "size": 20, + "alignment": "vertical and horizontal", + "fontScale": 1, + "spyable": true, + "show_queries": true, + "title": "用户IP" + }, + { + "span": 3, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=rs_timestamp:[NOW/MINUTE-15MINUTE%20TO%20NOW/MINUTE%2B1MINUTE]&facet=true&facet.field=user_ipaddress&facet.limit=10&facet.missing=true", + "custom": "" + }, + "mode": "count", + "field": "user_ipaddress", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10, + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": false, + "tilt": false, + "labels": true, + "arrangement": "horizontal", + "chart": "bar", + "counter_pos": "none", + "lastColor": "rgb(80,134,66)", + "spyable": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "title": "最高访问é‡IPå‰åå", + "logAxis": false, + "show_queries": true + }, + { + "span": 2, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=rs_timestamp:[NOW/MINUTE-15MINUTE%20TO%20NOW/MINUTE%2B1MINUTE]&facet=true&facet.field=os_name&facet.limit=10&facet.missing=true", + "custom": "" + }, + "mode": "count", + "field": "os_name", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": true, + "size": 10, + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": true, + "tilt": false, + "labels": true, + "arrangement": "horizontal", + "chart": "pie", + "counter_pos": "none", + "lastColor": "rgb(110,208,224)", + "spyable": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "title": "客户终端æ“作系统类型", + "logAxis": false, + "show_queries": true + }, + { + "span": 3, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=rs_timestamp:[NOW/MINUTE-15MINUTE%20TO%20NOW/MINUTE%2B1MINUTE]&facet=true&facet.field=responseElapsed&facet.limit=10&facet.missing=true", + "custom": "" + }, + "mode": "count", + "field": "responseElapsed", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10, + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": false, + "tilt": false, + "labels": true, + "arrangement": "horizontal", + "chart": "bar", + "counter_pos": "none", + "lastColor": "rgb(80,134,66)", + "spyable": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "title": "请求å“应时间统计", + "logAxis": false, + "show_queries": true + } + ] + }, + { + "title": "明细", + "height": "150px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 12, + "editable": true, + "type": "table", + "loadingEditor": false, + "status": "Stable", + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&fq=rs_timestamp:[NOW/MINUTE-15MINUTE%20TO%20NOW/MINUTE%2B1MINUTE]&sort=rs_timestamp desc&wt=json&rows=500", + "basic_query": "q=*%3A*&df=id&fq=rs_timestamp:[NOW/MINUTE-15MINUTE%20TO%20NOW/MINUTE%2B1MINUTE]&sort=rs_timestamp desc", + "custom": "" + }, + "size": 100, + "pages": 5, + "offset": 0, + "sort": [ + "id", + "desc" + ], + "group": "default", + "style": { + "font-size": "9pt" + }, + "overflow": "min-height", + "fields": [ + "app_id", + "rs_timestamp", + "doctype_s", + "connectElapsed", + "responseElapsed", + "page_urlhost", + "page_urlpath", + "useragent" + ], + "highlight": [], + "sortable": true, + "header": true, + "paging": true, + "field_list": true, + "trimFactor": 300, + "normTimes": true, + "spyable": false, + "saveOption": "json", + "exportSize": 500, + "exportAll": true, + "displayLinkIcon": true, + "imageFields": [], + "imgFieldWidth": "auto", + "imgFieldHeight": "85px", + "title": "实时请求明细", + "important_fields": [ + "app_id", + "event_id", + "rs_timestamp", + "doctype_s", + "id", + "connectElapsed", + "responseElapsed", + "page_urlhost", + "page_urlpath", + "useragent" + ], + "show_queries": true + } + ] + } + ], + "editable": true, + "index": { + "interval": "none", + "pattern": "[logstash-]YYYY.MM.DD", + "default": "_all" + }, + "style": "dark", + "failover": false, + "panel_hints": true, + "loader": { + "save_gist": false, + "save_elasticsearch": true, + "save_local": true, + "save_default": true, + "save_temp": true, + "save_temp_ttl_enable": true, + "save_temp_ttl": "30d", + "load_gist": true, + "load_elasticsearch": true, + "load_elasticsearch_size": 20, + "load_local": true, + "hide": false, + "dropdown_collections": false + }, + "solr": { + "server": "/solr/", + "core_name": "apm2", + "core_list": [ + "apm2_shard1_replica1" + ], + "global_params": "&df=id" + } +} \ No newline at end of file diff --git a/src/app/dashboards/realsight.apm.json b/src/app/dashboards/realsight.apm.json new file mode 100644 index 000000000..4de7c06b9 --- /dev/null +++ b/src/app/dashboards/realsight.apm.json @@ -0,0 +1,741 @@ +{ + "title": "RealSight APM (RealTime) 仪表盘", + "services": { + "query": { + "idQueue": [ + 1, + 2, + 3, + 4 + ], + "list": { + "0": { + "query": "*:*", + "alias": "", + "color": "#7EB26D", + "id": 0, + "pin": false, + "type": "lucene" + } + }, + "ids": [ + 0 + ] + }, + "filter": { + "idQueue": [ + 1, + 2, + 3, + 4 + ], + "list": { + "0": { + "from": "NOW/MINUTE-15MINUTE", + "to": "NOW/MINUTE%2B1MINUTE", + "field": "Timestamp_dt", + "type": "time", + "fromDateObj": "2016-08-27T06:38:31.990Z", + "toDateObj": "2016-08-27T06:53:31.990Z", + "mandate": "must", + "active": true, + "alias": "", + "id": 0 + } + }, + "ids": [ + 0 + ] + } + }, + "rows": [ + { + "title": "Query and Time Window", + "height": "50px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "error": "", + "span": 5, + "editable": true, + "type": "timepicker", + "loadingEditor": false, + "status": "Stable", + "mode": "relative", + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "7d", + "30d", + "90d", + "1y", + "5y" + ], + "timespan": "15m", + "timefield": "Timestamp_dt", + "timeformat": "", + "refresh": { + "enable": true, + "interval": 3, + "min": 1 + }, + "filter_id": 0, + "spyable": true, + "title": "Time Window" + }, + { + "error": false, + "span": 3, + "editable": true, + "group": [ + "default" + ], + "type": "query", + "label": "Search", + "history": [ + "*:*" + ], + "remember": 10, + "pinned": true, + "query": "*:*", + "title": "Search", + "spyable": true, + "def_type": "" + }, + { + "span": 4, + "editable": true, + "type": "hits", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&fq=Timestamp_dt:[NOW/MINUTE-15MINUTE%20TO%20NOW/MINUTE%2B1MINUTE]&wt=json&rows=0\n", + "basic_query": "", + "custom": "" + }, + "style": { + "font-size": "18pt" + }, + "arrangement": "horizontal", + "chart": "total", + "counter_pos": "above", + "donut": false, + "tilt": false, + "labels": true, + "spyable": true, + "title": "Total Alerts", + "show_queries": true + } + ] + }, + { + "title": "Filters", + "height": "50px", + "editable": true, + "collapse": true, + "collapsable": true, + "panels": [ + { + "error": false, + "span": 8, + "editable": true, + "spyable": true, + "group": [ + "default" + ], + "type": "filtering" + } + ] + }, + { + "title": "Graph", + "height": "250px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 2, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=Timestamp_dt:[NOW/MINUTE-15MINUTE%20TO%20NOW/MINUTE%2B1MINUTE]&facet=true&facet.field=Health&facet.limit=10&facet.missing=true", + "custom": "" + }, + "mode": "count", + "field": "Health", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": true, + "size": 10, + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": true, + "tilt": false, + "labels": true, + "arrangement": "horizontal", + "chart": "pie", + "counter_pos": "none", + "lastColor": "rgb(110,208,224)", + "spyable": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "title": "Applications Health", + "logAxis": false, + "show_queries": true + }, + { + "span": 3, + "editable": true, + "type": "tagcloud", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=Timestamp_dt:[NOW/MINUTE-15MINUTE%20TO%20NOW/MINUTE%2B1MINUTE]&facet=true&facet.field=OnlineUserNum_total&facet.limit=20", + "custom": "" + }, + "field": "OnlineUserNum_total", + "size": 20, + "alignment": "vertical and horizontal", + "fontScale": 1, + "spyable": true, + "show_queries": true, + "title": "Users" + }, + { + "span": 2, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=Timestamp_dt:[NOW/MINUTE-15MINUTE%20TO%20NOW/MINUTE%2B1MINUTE]&facet=true&facet.field=OnlineUserNum_total&facet.limit=10&facet.missing=true", + "custom": "" + }, + "mode": "count", + "field": "OnlineUserNum_total", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10, + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": false, + "tilt": false, + "labels": true, + "arrangement": "horizontal", + "chart": "bar", + "counter_pos": "none", + "lastColor": "rgb(80,134,66)", + "spyable": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "title": "Top Users", + "logAxis": false, + "show_queries": true + }, + { + "span": 2, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=Timestamp_dt:[NOW/MINUTE-15MINUTE%20TO%20NOW/MINUTE%2B1MINUTE]&facet=true&facet.field=Memory_used&facet.limit=10&facet.missing=true", + "custom": "" + }, + "mode": "count", + "field": "Memory_used", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10, + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": false, + "tilt": false, + "labels": true, + "arrangement": "horizontal", + "chart": "bar", + "counter_pos": "none", + "lastColor": "rgb(80,134,66)", + "spyable": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "title": "Memory_used", + "logAxis": false, + "show_queries": true + }, + { + "span": 2, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=Timestamp_dt:[NOW/MINUTE-15MINUTE%20TO%20NOW/MINUTE%2B1MINUTE]&facet=true&facet.field=HeapPercent&facet.limit=150&facet.missing=true", + "custom": "" + }, + "mode": "count", + "field": "HeapPercent", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 150, + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": false, + "tilt": false, + "labels": true, + "arrangement": "horizontal", + "chart": "table", + "counter_pos": "none", + "lastColor": "", + "spyable": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "title": "HeapPercent", + "logAxis": false, + "show_queries": true + } + ] + }, + { + "title": "Histogram row", + "height": "150px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 12, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "count", + "time_field": "Timestamp_dt", + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&wt=json&rows=0&fq=Timestamp_dt:[NOW/HOUR-1HOUR%20TO%20NOW/HOUR-1HOUR]&facet=true&facet.range=Timestamp_dt&facet.range.start=NOW/HOUR-1HOUR&facet.range.end=NOW/HOUR%2B1HOUR&facet.range.gap=%2B30SECOND\n", + "custom": "" + }, + "max_rows": 100000, + "value_field": "polarityCount_i", + "group_field": "polarity_s", + "auto_int": true, + "resolution": 100, + "interval": "10s", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 0, + "linewidth": 3, + "timezone": "browser", + "spyable": true, + "zoomlinks": true, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "Threats Histogram", + "lines_smooth": false, + "show_queries": true + } + ] + }, + { + "title": "Table", + "height": "150px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 12, + "editable": true, + "type": "table", + "loadingEditor": false, + "status": "Stable", + "queries": { + "mode": "all", + "ids": [ + 0 + ], + "query": "q=*%3A*&df=id&fq=Timestamp_dt:[NOW/MINUTE-15MINUTE%20TO%20NOW/MINUTE%2B1MINUTE]&sort=Timestamp_dt desc&wt=json&rows=500", + "basic_query": "q=*%3A*&df=id&fq=Timestamp_dt:[NOW/MINUTE-15MINUTE%20TO%20NOW/MINUTE%2B1MINUTE]&sort=Timestamp_dt desc", + "custom": "" + }, + "size": 100, + "pages": 5, + "offset": 0, + "sort": [ + "Timestamp_dt", + "desc" + ], + "group": "default", + "style": { + "font-size": "9pt" + }, + "overflow": "min-height", + "fields": [ + "Timestamp_dt", + "ActiveThreadsNum", + "DiskFree", + "ERROR_text" + ], + "highlight": [], + "sortable": true, + "header": true, + "paging": true, + "field_list": true, + "trimFactor": 300, + "normTimes": true, + "spyable": false, + "saveOption": "json", + "exportSize": 500, + "exportAll": true, + "displayLinkIcon": true, + "imageFields": [], + "imgFieldWidth": "auto", + "imgFieldHeight": "85px", + "title": "Events", + "important_fields": [ + "_version_", + "Timestamp_dt", + "doctype_s", + "id", + "CPU_used", + "screenName_s", + "tag_s", + "tag_ss", + "SwapPercent" + ], + "show_queries": true + } + ] + } + ], + "editable": true, + "index": { + "interval": "none", + "pattern": "[logstash-]YYYY.MM.DD", + "default": "_all" + }, + "style": "dark", + "failover": false, + "panel_hints": true, + "loader": { + "save_gist": false, + "save_elasticsearch": true, + "save_local": true, + "save_default": true, + "save_temp": true, + "save_temp_ttl_enable": true, + "save_temp_ttl": "30d", + "load_gist": true, + "load_elasticsearch": true, + "load_elasticsearch_size": 20, + "load_local": true, + "hide": false, + "dropdown_collections": false + }, + "solr": { + "server": "/solr/", + "core_name": "apm", + "core_list": [ + "apm_shard1_replica1" + ], + "global_params": "&df=id" + } +} \ No newline at end of file diff --git a/src/app/dashboards/syslog.json b/src/app/dashboards/syslog.json old mode 100755 new mode 100644 diff --git a/src/app/dashboards/tubiaoxiu.json b/src/app/dashboards/tubiaoxiu.json new file mode 100644 index 000000000..09a4ef6fc --- /dev/null +++ b/src/app/dashboards/tubiaoxiu.json @@ -0,0 +1,1678 @@ +{ + "title": "Neusoftï¼å›¾è¡¨ç§€å®žæ—¶ä»ªè¡¨ç›˜", + "services": { + "query": { + "idQueue": [ + 3, + 4 + ], + "list": { + "0": { + "query": "*:*", + "alias": "Risk% ", + "color": "#EA6460", + "id": 0, + "pin": false, + "type": "lucene" + }, + "1": { + "id": 1, + "color": "#E5AC0E", + "query": "*:*", + "alias": "Warning% ", + "pin": false + }, + "2": { + "id": 2, + "color": "#1F78C1", + "query": "*:*", + "alias": "Normal% ", + "pin": false + } + }, + "ids": [ + 0, + 1, + 2 + ] + }, + "filter": { + "idQueue": [ + 1, + 2, + 3 + ], + "list": { + "0": { + "from": "NOW/HOUR-24HOUR", + "to": "NOW/HOUR%2B1HOUR", + "field": "rs_timestamp", + "type": "time", + "fromDateObj": "2017-03-02T09:01:10.858Z", + "toDateObj": "2017-03-03T09:01:10.858Z", + "mandate": "must", + "active": true, + "alias": "", + "id": 0 + } + }, + "ids": [ + 0 + ] + } + }, + "rows": [ + { + "title": "Query and Time Window", + "height": "50px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "error": "", + "span": 8, + "editable": true, + "type": "timepicker", + "loadingEditor": false, + "status": "Stable", + "mode": "relative", + "time_options": [ + "6h", + "12h", + "24h", + "48h", + "72h", + "5d", + "7d", + "10d", + "15d", + "30d", + "90d", + "180d", + "1y", + "3y", + "5y" + ], + "timespan": "24h", + "timefield": "rs_timestamp", + "timeformat": "", + "refresh": { + "enable": false, + "interval": 100, + "min": 3 + }, + "filter_id": 0, + "spyable": true, + "title": "æ—¶é—´è½´" + }, + { + "span": 4, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=user_ipaddress&facet.limit=100000&facet.missing=true&f.user_ipaddress.facet.sort=count&fq=app_id:Platform System", + "custom": "&fq=app_id:Platform System" + }, + "mode": "count", + "field": "user_ipaddress", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 100000, + "sortBy": "count", + "order": "descending", + "style": { + "font-size": "48pt" + }, + "donut": false, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "horizontal", + "chart": "hits", + "counter_pos": "none", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "图表秀 ï¼ åœ¨çº¿ç”¨æˆ·", + "threshold_first": 3000, + "threshold_second": 5000, + "fontsize": 20 + } + ] + }, + { + "title": "WARNING", + "height": "550px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 3, + "editable": true, + "type": "map", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&rows=0&facet=true&facet.field=ipcode&facet.limit=100000", + "custom": "&fq=app_id:Platform System" + }, + "mode": "count", + "field": "ipcode", + "stats_field": "", + "decimal_points": 0, + "map": "china", + "useNames": false, + "colors": [ + "#A0E2E2", + "#265656" + ], + "size": 100000, + "exclude": [], + "spyable": true, + "index_limit": 0, + "show_queries": true, + "title": "å›¾è¡¨ç§€ï¼ ç”¨æˆ·åˆ†å¸ƒ" + }, + { + "span": 6, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=connectElapsed&facet.limit=100000&facet.missing=true&f.connectElapsed.facet.sort=count&fq=app_id:Platform System", + "custom": "&fq=app_id:Platform System" + }, + "mode": "count", + "field": "connectElapsed", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 100000, + "sortBy": "count", + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": false, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "horizontal", + "chart": "dashboard", + "counter_pos": "none", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "å›¾è¡¨ç§€ï¼ å¥åº·åº¦", + "threshold_first": 5000, + "threshold_second": 10000, + "fontsize": 20 + }, + { + "span": 3, + "editable": true, + "type": "terms", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=user_ipaddress&facet.limit=100000&facet.missing=true&f.user_ipaddress.facet.sort=count&fq=app_id:Platform System", + "custom": "&fq=app_id:Platform System" + }, + "mode": "count", + "field": "user_ipaddress", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 100000, + "sortBy": "count", + "order": "descending", + "style": { + "font-size": "10pt" + }, + "donut": false, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "horizontal", + "chart": "ebar", + "counter_pos": "none", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "图表秀ï¼ç”¨æˆ·ç‚¹å‡»TOP5", + "threshold_first": 3000, + "threshold_second": 5000, + "fontsize": 20 + } + ] + }, + { + "title": "Change", + "height": "80px", + "editable": true, + "collapse": true, + "collapsable": true, + "panels": [ + { + "span": 4, + "editable": true, + "type": "ticker", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-03-02T09:01:10.858Z&facet.range.end=2017-03-03T09:01:10.858Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-03-02T08:01:10.858Z&facet.range.end=2017-03-03T08:01:10.858Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-03-02T09:01:10.858Z&facet.range.end=2017-03-03T09:01:10.858Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-03-02T08:01:10.858Z&facet.range.end=2017-03-03T08:01:10.858Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-03-02T09:01:10.858Z&facet.range.end=2017-03-03T09:01:10.858Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-03-02T08:01:10.858Z&facet.range.end=2017-03-03T08:01:10.858Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\n" + }, + "style": { + "font-size": "14pt" + }, + "ago": "1h", + "arrangement": "horizontal", + "spyable": true, + "show_queries": false, + "title": "SSA SYSTEM-Risk chaange(hour)" + }, + { + "span": 4, + "editable": true, + "type": "ticker", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-03-02T09:01:10.858Z&facet.range.end=2017-03-03T09:01:10.858Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-03-01T09:01:10.858Z&facet.range.end=2017-03-02T09:01:10.858Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-03-02T09:01:10.858Z&facet.range.end=2017-03-03T09:01:10.858Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-03-01T09:01:10.858Z&facet.range.end=2017-03-02T09:01:10.858Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-03-02T09:01:10.858Z&facet.range.end=2017-03-03T09:01:10.858Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-03-01T09:01:10.858Z&facet.range.end=2017-03-02T09:01:10.858Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\n" + }, + "style": { + "font-size": "14pt" + }, + "ago": "1d", + "arrangement": "horizontal", + "spyable": true, + "show_queries": true, + "title": "SSA SYSTEM-Risk chaange(day)" + }, + { + "span": 4, + "editable": true, + "type": "ticker", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-03-02T09:01:10.858Z&facet.range.end=2017-03-03T09:01:10.858Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-02-23T09:01:10.858Z&facet.range.end=2017-02-24T09:01:10.858Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-03-02T09:01:10.858Z&facet.range.end=2017-03-03T09:01:10.858Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-02-23T09:01:10.858Z&facet.range.end=2017-02-24T09:01:10.858Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-03-02T09:01:10.858Z&facet.range.end=2017-03-03T09:01:10.858Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n\nq=*%3A*&wt=json&rows=0&facet=true&facet.range=rs_timestamp&facet.range.start=2017-02-23T09:01:10.858Z&facet.range.end=2017-02-24T09:01:10.858Z&facet.range.gap=%2B2DAY&facet.range.hardend=true&facet.range.other=between\n-----------\n" + }, + "style": { + "font-size": "14pt" + }, + "ago": "1w", + "arrangement": "horizontal", + "spyable": true, + "show_queries": true, + "title": "SSA SYSTEM-Risk chaange(week)" + } + ] + }, + { + "title": "EVENT COUNT", + "height": "200px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 12, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "counts", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=connectElapsed%3A%5B10000%20TO%20*%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/HOUR-24HOUR&facet.range.end=NOW/HOUR%2B1HOUR&facet.range.gap=%2B10MINUTE\nq=connectElapsed%3A%5B5000%20TO%209999%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/HOUR-24HOUR&facet.range.end=NOW/HOUR%2B1HOUR&facet.range.gap=%2B10MINUTE\nq=connectElapsed%3A%5B0%20TO%204999%5D&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.range=rs_timestamp&facet.range.start=NOW/HOUR-24HOUR&facet.range.end=NOW/HOUR%2B1HOUR&facet.range.gap=%2B10MINUTE\n", + "custom": "&fq=app_id:Platform System" + }, + "max_rows": 100000, + "value_field": "connectElapsed", + "group_field": null, + "sum_value": false, + "auto_int": true, + "resolution": 100, + "interval": "10m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": true, + "bars": false, + "stack": true, + "points": false, + "lines": true, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": true, + "show_queries": true, + "tooltip": { + "value_type": "individual", + "query_as_alias": false + }, + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "图表秀ï¼äº‹åŠ¡ç»Ÿè®¡", + "reverse": 0, + "segment": 3, + "threshold_first": 5000, + "threshold_second": 10000, + "threshold_third": 3000, + "total_first": "%" + } + ] + }, + { + "title": "response time", + "height": "200px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 6, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=responseElapsed%3A%5B5000%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp responseElapsed\nq=responseElapsed%3A%5B3000%20TO%204999%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp responseElapsed\nq=responseElapsed%3A%5B0%20TO%202999%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp responseElapsed\n", + "custom": "&fq=app_id:Platform System&fq=responseElapsed:[0 TO 1000000]" + }, + "max_rows": 100000, + "value_field": "responseElapsed", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "10m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "图表秀ï¼å“应时间(ms)", + "reverse": 0, + "segment": 3, + "threshold_first": 3000, + "threshold_second": 5000, + "threshold_third": 3000, + "total_first": "%" + }, + { + "span": 6, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=connectElapsed%3A%5B10000%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp connectElapsed\nq=connectElapsed%3A%5B5000%20TO%209999%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp connectElapsed\nq=connectElapsed%3A%5B0%20TO%204999%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp connectElapsed\n", + "custom": "&fq=app_id:Platform System&fq=connectElapsed:[0 TO 100000]" + }, + "max_rows": 100000, + "value_field": "connectElapsed", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "10m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 3, + "linewidth": 1, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "å›¾è¡¨ç§€ï¼æœåŠ¡è¿žæŽ¥æ—¶é—´(MS)", + "reverse": 0, + "segment": 3, + "threshold_first": 5000, + "threshold_second": 10000, + "threshold_third": 3000, + "total_first": "%" + } + ] + }, + { + "title": "RESPONSE", + "height": "200px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 6, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=domElapsed%3A%5B5000%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domElapsed\nq=domElapsed%3A%5B3000%20TO%204999%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domElapsed\nq=domElapsed%3A%5B0%20TO%202999%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domElapsed\n", + "custom": "&fq=-domElapsed:[40000 TO *]&fq=app_id:Platform System" + }, + "max_rows": 100000, + "value_field": "domElapsed", + "group_field": null, + "auto_int": true, + "resolution": 200, + "interval": "5m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 4, + "linewidth": 3, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": false, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "图表秀ï¼é¡µé¢åŠ è½½æ—¶é—´(ms)", + "reverse": 0, + "segment": 3, + "threshold_first": 3000, + "threshold_second": 5000, + "threshold_third": 3000, + "total_first": "%" + }, + { + "span": 6, + "editable": true, + "type": "histogram", + "loadingEditor": false, + "mode": "value", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=domContentLoadedElapsed%3A%5B5000%20TO%20*%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domContentLoadedElapsed\nq=domContentLoadedElapsed%3A%5B3000%20TO%204999%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domContentLoadedElapsed\nq=domContentLoadedElapsed%3A%5B0%20TO%202999%5D&wt=json&rows=100000&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&fl=rs_timestamp domContentLoadedElapsed\n", + "custom": "&fq=app_id:Platform System" + }, + "max_rows": 100000, + "value_field": "domContentLoadedElapsed", + "group_field": null, + "auto_int": true, + "resolution": 100, + "interval": "10m", + "intervals": [ + "auto", + "1s", + "1m", + "5m", + "10m", + "30m", + "1h", + "3h", + "12h", + "1d", + "1w", + "1M", + "1y" + ], + "fill": 0, + "linewidth": 3, + "timezone": "browser", + "spyable": true, + "zoomlinks": false, + "bars": true, + "stack": true, + "points": false, + "lines": false, + "lines_smooth": false, + "legend": true, + "x-axis": true, + "y-axis": true, + "percentage": false, + "interactive": true, + "options": false, + "show_queries": true, + "tooltip": { + "value_type": "cumulative", + "query_as_alias": false + }, + "title": "图表秀ï¼å†…容加载时间(ms)", + "reverse": 0, + "segment": 3, + "threshold_first": 3000, + "threshold_second": 5000, + "threshold_third": 3000, + "total_first": "%" + } + ] + }, + { + "title": "time", + "height": "200px", + "editable": true, + "collapse": true, + "collapsable": true, + "panels": [] + }, + { + "title": "Message", + "height": "190px", + "editable": true, + "collapse": true, + "collapsable": true, + "panels": [] + }, + { + "title": "", + "height": "250px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 6, + "editable": true, + "type": "pies", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=dvce_type&facet.limit=100000&facet.missing=true&f.dvce_type.facet.sort=count&fq=app_id:Platform System", + "custom": "&fq=app_id:Platform System" + }, + "mode": "count", + "field": "dvce_type", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 100000, + "sortBy": "count", + "order": "descending", + "fontsize": 14, + "donut": true, + "tilt": false, + "labels": true, + "logAxis": false, + "arrangement": "vertical", + "RoseType": "area", + "chart": "pie", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#1a93f9", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "eLegend": true, + "title": "图表秀 ï¼ç”¨æˆ·è®¾å¤‡", + "ylabels": true + }, + { + "span": 6, + "editable": true, + "type": "tagcloud", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&rows=0&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=br_name&facet.limit=100000", + "custom": "&fq=app_id:Platform System" + }, + "field": "br_name", + "size": 100000, + "alignment": "horizontal", + "fontScale": 4, + "ignoreStopWords": false, + "spyable": true, + "show_queries": true, + "title": "å›¾è¡¨ç§€ï¼ ç”¨æˆ·æµè§ˆå™¨" + } + ] + }, + { + "title": "PIE", + "height": "250px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 6, + "editable": true, + "type": "pies", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=os_name&facet.limit=10&facet.missing=true&f.os_name.facet.sort=count&fq=app_id:Platform System", + "custom": "&fq=app_id:Platform System" + }, + "mode": "count", + "field": "os_name", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10, + "sortBy": "count", + "order": "descending", + "fontsize": 12, + "donut": false, + "tilt": false, + "labels": true, + "ylabels": true, + "logAxis": false, + "arrangement": "vertical", + "RoseType": "area", + "chart": "bars", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "å›¾è¡¨ç§€ï¼ ç”¨æˆ·æ“作系统 top 10" + }, + { + "span": 6, + "editable": true, + "type": "pies", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=os_family&facet.limit=10000&facet.missing=true&f.os_family.facet.sort=count", + "custom": "" + }, + "mode": "count", + "field": "os_family", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10000, + "sortBy": "count", + "order": "descending", + "fontsize": 12, + "donut": false, + "tilt": false, + "labels": true, + "ylabels": true, + "logAxis": false, + "arrangement": "vertical", + "RoseType": "area", + "chart": "radar", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "图表秀-用户æ“作系统对比" + } + ] + }, + { + "title": "IP", + "height": "250px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 6, + "editable": true, + "type": "pies", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=Isp&facet.limit=10&facet.missing=true&f.Isp.facet.sort=count", + "custom": "" + }, + "mode": "count", + "field": "Isp", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10, + "sortBy": "count", + "order": "descending", + "fontsize": 12, + "donut": false, + "tilt": false, + "labels": true, + "ylabels": true, + "logAxis": false, + "arrangement": "vertical", + "RoseType": "area", + "chart": "bar", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#1a75f9", + "#1ab0f9", + "#42d3f0", + "#e59d87", + "#759aa0", + "#dc6b67", + "#efdd79", + "#8dc1aa", + "#ea7d52", + "#8dace7", + "#a6a1e1", + "#FECDA3", + "#FED980", + "#bcf924", + "#f9ac24", + "#8224f9", + "#24e5f9", + "#f96524" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "图表秀 ï¼ ç”¨æˆ·æ¥æº top 10", + "eLegend": true, + "error": false + }, + { + "span": 6, + "editable": true, + "type": "pies", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=City&facet.limit=10000&facet.missing=true&f.City.facet.sort=count", + "custom": "" + }, + "mode": "count", + "field": "City", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10000, + "sortBy": "count", + "order": "descending", + "fontsize": 12, + "donut": false, + "tilt": false, + "labels": false, + "ylabels": true, + "logAxis": false, + "arrangement": "vertical", + "RoseType": "area", + "chart": "pie", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#1a75f9", + "#1ab0f9", + "#42d3f0", + "#e59d87", + "#759aa0", + "#dc6b67", + "#efdd79", + "#8dc1aa", + "#ea7d52", + "#8dace7", + "#a6a1e1", + "#FECDA3", + "#FED980", + "#bcf924", + "#f9ac24", + "#8224f9", + "#24e5f9", + "#f96524", + "#f4fd8b", + "#b3f457", + "#80f457", + "#60f457", + "#576ef4", + "#579ef4", + "#57cef4", + "#f45b57", + "#7157f4", + "#f457e9", + "#8406e0", + "#2e06e0", + "#a1e006", + "#3de006", + "#06e045", + "#347b93" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "eLegend": true, + "title": "图表秀-用户城市分布", + "error": false + } + ] + }, + { + "title": "111", + "height": "550px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 12, + "editable": true, + "type": "china", + "loadingEditor": false, + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&wt=json&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=City&facet.limit=10000&facet.missing=true&f.City.facet.sort=count", + "custom": "" + }, + "mode": "count", + "field": "City", + "stats_field": "", + "decimal_points": 0, + "exclude": [], + "missing": false, + "other": false, + "size": 10000, + "sortBy": "count", + "order": "descending", + "logAxis": false, + "chart": "cmap", + "exportSize": 10000, + "lastColor": "", + "spyable": true, + "show_queries": true, + "chartColors": [ + "#7EB26D", + "#EAB839", + "#6ED0E0", + "#EF843C", + "#E24D42", + "#1F78C1", + "#BA43A9", + "#705DA0", + "#508642", + "#CCA300", + "#447EBC", + "#C15C17", + "#890F02", + "#0A437C", + "#6D1F62", + "#584477", + "#B7DBAB", + "#F4D598", + "#70DBED", + "#F9BA8F", + "#F29191", + "#82B5D8", + "#E5A8E2", + "#AEA2E0", + "#629E51", + "#E5AC0E", + "#64B0C8", + "#E0752D", + "#BF1B00", + "#0A50A1", + "#962D82", + "#614D93", + "#9AC48A", + "#F2C96D", + "#65C5DB", + "#F9934E", + "#EA6460", + "#5195CE", + "#D683CE", + "#806EB7", + "#3F6833", + "#967302", + "#2F575E", + "#99440A", + "#58140C", + "#052B51", + "#511749", + "#3F2B5B", + "#E0F9D7", + "#FCEACA", + "#CFFAFF", + "#F9E2D2", + "#FCE2DE", + "#BADFF4", + "#F9D9F9", + "#DEDAF7" + ], + "refresh": { + "enable": false, + "interval": 2 + }, + "title": "图表秀 - 地域分布", + "error": false + } + ] + }, + { + "title": "Detail", + "height": "150px", + "editable": true, + "collapse": false, + "collapsable": true, + "panels": [ + { + "span": 12, + "editable": true, + "type": "fullTextSearch", + "loadingEditor": false, + "status": "Stable", + "queries": { + "mode": "all", + "ids": [ + 0, + 1, + 2 + ], + "query": "q=*%3A* OR *%3A* OR *%3A*&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=os_name&facet.field=useragent&facet.field=page_url&facet.field=br_name&facet.field=UsedMemery&facet.field=user_ipaddress&facet.field=dvce_type&facet.field=app_id&wt=json&rows=1500&hl=true&hl.fl=useragent", + "basic_query": "q=*%3A* OR *%3A* OR *%3A*&fq=rs_timestamp:[NOW/HOUR-24HOUR%20TO%20NOW/HOUR%2B1HOUR]&facet=true&facet.field=os_name&facet.field=useragent&facet.field=page_url&facet.field=br_name&facet.field=UsedMemery&facet.field=user_ipaddress&facet.field=dvce_type&facet.field=app_id", + "custom": "&fq=app_id:Platform System" + }, + "size": 5, + "pages": 300, + "offset": 0, + "group": "default", + "sort": [ + "os_family" + ], + "style": { + "font-size": "12pt" + }, + "overflow": "min-height", + "fields": [ + "os_name", + "useragent", + "page_url", + "br_name", + "UsedMemery", + "user_ipaddress", + "dvce_type", + "app_id" + ], + "highlight": [], + "sortable": false, + "header": true, + "paging": true, + "field_list": true, + "trimFactor": 200, + "normTimes": true, + "spyable": true, + "saveOption": "json", + "exportSize": 1500, + "exportAll": true, + "facet_limit": 100000, + "foundResults": true, + "show_queries": true, + "title": "图表秀ï¼è¯¦ç»†ä¿¡æ¯", + "header_field": "app_id", + "body_field": "useragent", + "url_field": "page_url", + "error": false + } + ] + }, + { + "title": "context time", + "height": "200px", + "editable": true, + "collapse": true, + "collapsable": true, + "panels": [ + { + "error": false, + "span": 6, + "editable": true, + "type": "filtering", + "loadingEditor": false, + "spyable": true + }, + { + "error": false, + "span": 6, + "editable": true, + "type": "query", + "loadingEditor": false, + "query": "*:*", + "pinned": true, + "history": [ + "*:*", + "responseElapsed:[0 TO 20000]", + "responseElapsed:[20000 TO 30000]", + "responseElapsed:[30000 TO *]", + "responseElapsed:[20000 TO 19999]", + "responseElapsed:[0 TO 15000]", + "responseElapsed:[15000 TO 19999]", + "responseElapsed:[20000 TO *]" + ], + "spyable": true, + "remember": 10 + } + ] + } + ], + "editable": true, + "index": { + "interval": "none", + "pattern": "[logstash-]YYYY.MM.DD", + "default": "_all" + }, + "style": "dark", + "failover": false, + "panel_hints": true, + "loader": { + "save_gist": false, + "save_elasticsearch": true, + "save_local": true, + "save_default": true, + "save_temp": true, + "save_temp_ttl_enable": true, + "save_temp_ttl": "30d", + "load_gist": true, + "load_elasticsearch": true, + "load_elasticsearch_size": 20, + "load_local": true, + "hide": false, + "dropdown_collections": false, + "save_as_public": false + }, + "solr": { + "server": "http://101.201.82.138:8080/solr/", + "core_name": "apm3", + "core_list": [ + "apm", + "apm3" + ], + "global_params": "" + }, + "username": "guest" +} \ No newline at end of file diff --git a/src/app/directives/addPanel.js b/src/app/directives/addPanel.js old mode 100755 new mode 100644 diff --git a/src/app/directives/all.js b/src/app/directives/all.js old mode 100755 new mode 100644 diff --git a/src/app/directives/arrayJoin.js b/src/app/directives/arrayJoin.js old mode 100755 new mode 100644 diff --git a/src/app/directives/confirmClick.js b/src/app/directives/confirmClick.js old mode 100755 new mode 100644 diff --git a/src/app/directives/dashUpload.js b/src/app/directives/dashUpload.js old mode 100755 new mode 100644 index 899cac4a3..52150e21f --- a/src/app/directives/dashUpload.js +++ b/src/app/directives/dashUpload.js @@ -40,4 +40,4 @@ define([ } }; }); - }); \ No newline at end of file + }); diff --git a/src/app/directives/kibanaPanel.js b/src/app/directives/kibanaPanel.js old mode 100755 new mode 100644 index 45a959fc9..45b8a53ec --- a/src/app/directives/kibanaPanel.js +++ b/src/app/directives/kibanaPanel.js @@ -7,7 +7,7 @@ function (angular) { angular .module('kibana.directives') .directive('kibanaPanel', function($compile) { - var container = '
'; + var container = '
'; var editorTemplate = @@ -25,47 +25,47 @@ function (angular) { 'onStop:\'panelMoveStop\''+ '}" ng-model="row.panels">{{panel.type}}'+ '' + - '' + + '' + '{{panel.type}}'+ '' + - '' + + '' + ''+ - ''+ + ''+ '' + - '' + + '' + ''+ - ''+ + ''+ '' + - '' + + '' + + ''+ + '' + + + '' + '' + '' + - '' + - '' + - ''+ + '' + + ''+ '' + - '' + - ''+ - '' + // bettermap fitBound action - - '' + + '' + '' + - '' + + '' + '' + '' + @@ -76,13 +76,13 @@ function (angular) { // 'ng-class="dropdown.icon" class="pointer">'+ // '' + - '' + + '' + ''+ '' + ''+ '' + - '' + + '' + '{{panel.title}}' + ''+ diff --git a/src/app/directives/ngBlur.js b/src/app/directives/ngBlur.js old mode 100755 new mode 100644 diff --git a/src/app/directives/ngModelOnBlur.js b/src/app/directives/ngModelOnBlur.js old mode 100755 new mode 100644 diff --git a/src/app/directives/tip.js b/src/app/directives/tip.js old mode 100755 new mode 100644 diff --git a/src/app/filters/all.js b/src/app/filters/all.js old mode 100755 new mode 100644 diff --git a/src/app/panels/ad/editor.html b/src/app/panels/ad/editor.html new file mode 100644 index 000000000..5b4475f31 --- /dev/null +++ b/src/app/panels/ad/editor.html @@ -0,0 +1,32 @@ +
+
+ + +
+
+ +
+ + +
Model Settings
+
+ + +
+
+ + +
+
+ + +
+
+ +
Tooltip Settings
+
+
+ + +
+
diff --git a/src/app/panels/rangeFacet/interval.js b/src/app/panels/ad/interval.js similarity index 100% rename from src/app/panels/rangeFacet/interval.js rename to src/app/panels/ad/interval.js diff --git a/src/app/panels/ad/module.html b/src/app/panels/ad/module.html new file mode 100644 index 000000000..6c294aaf3 --- /dev/null +++ b/src/app/panels/ad/module.html @@ -0,0 +1,14 @@ +
+
+ + +
+
+ +
diff --git a/src/app/panels/ad/module.js b/src/app/panels/ad/module.js new file mode 100644 index 000000000..2431afa4d --- /dev/null +++ b/src/app/panels/ad/module.js @@ -0,0 +1,533 @@ +/* + + ## Anomaly Detection + + ### Parameters + * auto_int :: Auto calculate data point interval? + * resolution :: If auto_int is enables, shoot for this many data points, rounding to + sane intervals + * interval :: Datapoint interval in elasticsearch date math format (eg 1d, 1w, 1y, 5y) + * fill :: Only applies to line charts. Level of area shading from 0-10 + * linewidth :: Only applies to line charts. How thick the line should be in pixels + While the editor only exposes 0-10, this can be any numeric value. + Set to 0 and you'll get something like a scatter plot + * timezone :: This isn't totally functional yet. Currently only supports browser and utc. + browser will adjust the x-axis labels to match the timezone of the user's + browser + * spyable :: Dislay the 'eye' icon that show the last elasticsearch query + * zoomlinks :: Show the zoom links? + * bars :: Show bars in the chart + * stack :: Stack multiple queries. This generally a crappy way to represent things. + You probably should just use a line chart without stacking + * points :: Should circles at the data points on the chart + * lines :: Line chart? Sweet. + * legend :: Show the legend? + * x-axis :: Show x-axis labels and grid lines + * y-axis :: Show y-axis labels and grid lines + * interactive :: Allow drag to select time range + +*/ +define([ + 'angular', + 'app', + 'jquery', + 'underscore', + 'kbn', + 'moment', + './timeSeries' +], +function (angular, app, $, _, kbn, moment, timeSeries) { + 'use strict'; + var module = angular.module('kibana.panels.ad', []); + app.useModule(module); + + var DEBUG = false; + console.log('AD DEBUG : ' + DEBUG); + module.controller('ad', function($scope, $q, $http, $routeParams, querySrv, dashboard, filterSrv, alertSrv) { + $scope.panelMeta = { + modals : [ + { + description: "Inspect", + icon: "icon-info-sign", + partial: "app/partials/inspector.html", + show: $scope.panel.spyable + } + ], + editorTabs : [ + { + title:'Queries', + src:'app/partials/querySelect.html' + } + ], + status : "Stable", + description : "A bucketed time series chart of the current query, including all applied time and non-time filters, when used in count mode. Uses Solr’s facet.range query parameters. In values mode, it plots the value of a specific field over time, and allows the user to group field values by a second field." + }; + + // Set and populate defaults + var _d = { + mode : 'value', + queries : { + mode : 'all', + ids : [], + query : '*:*', + custom : '' + }, + max_rows : 1000, // maximum number of rows returned from Solr (also use this for group.limit to simplify UI setting) + cut_number : 100, + anomaly_th : 0.70, + reverse : 0, + group_field : null, + auto_int : true, + total_first : '%', + fontsize : 20, + field_color : '#209bf8', + resolution : 100, + value_sort : 'rs_timestamp', + interval : '5m', + intervals : ['auto','1s','1m','5m','10m','30m','1h','3h','12h','1d','1w','1M','1y'], + fill : 0, + linewidth : 3, + chart : 'stacking', + chartColors : ['#209bf8', '#f4d352','#ccf452','#8cf452','#3cee2b','#f467d8','#2fd7ee'], + timezone : 'browser', // browser, utc or a standard timezone + spyable : true, + zoomlinks : true, + bars : true, + stack : true, + label : true, + points : false, + lines : false, + lines_smooth: false, // Enable 'smooth line' mode by removing zero values from the plot. + legend : true, + 'x-axis' : true, + 'y-axis' : true, + percentage : false, + interactive : true, + options : true, + show_queries: true, + tooltip : { + value_type: 'cumulative', + query_as_alias: false + }, + jobid : '', + job_status: 'Ready' + }; + + _.defaults($scope.panel,_d); + + $scope.init = function() { + // Hide view options by default + if (DEBUG) { console.log('init'); } + $scope.options = false; + $scope.$on('refresh',function(){ + $scope.get_data(); + }); + + $scope.get_data(); + + }; + + $scope.set_interval = function(interval) { + if(interval !== 'auto') { + $scope.panel.auto_int = false; + $scope.panel.interval = interval; + } else { + $scope.panel.auto_int = true; + } + }; + + $scope.interval_label = function(interval) { + return $scope.panel.auto_int && interval === $scope.panel.interval ? interval+" (auto)" : interval; + }; + + $scope.set_refresh = function (state) { + $scope.refresh = state; + // if 'count' mode is selected, set decimal_points to zero automatically. + if ($scope.panel.mode === 'count') { + $scope.panel.decimal_points = 0; + } + $scope.get_data(); + }; + /** + * The time range effecting the panel + * @return {[type]} [description] + */ + $scope.get_time_range = function () { + var range = $scope.range = filterSrv.timeRange('min'); + return range; + }; + + $scope.get_interval = function () { + var interval = $scope.panel.interval, + range; + if ($scope.panel.auto_int) { + range = $scope.get_time_range(); + if (range) { + interval = kbn.secondsToHms( + kbn.calculate_interval(range.from, range.to, $scope.panel.resolution, 0) / 1000 + ); + } + } + $scope.panel.interval = interval || '10m'; + return $scope.panel.interval; + }; + + /** + * Fetch the data for a chunk of a queries results. Multiple segments occur when several indicies + * need to be consulted (like timestamped logstash indicies) + * + * The results of this function are stored on the scope's data property. This property will be an + * array of objects with the properties info, time_series, and hits. These objects are used in the + * render_panel function to create the historgram. + * + * !!! Solr does not need to fetch the data in chunk because it uses a facet search and retrieve + * !!! all events from a single query. + * + * @param {number} segment The segment count, (0 based) + * @param {number} query_id The id of the query, generated on the first run and passed back when + * this call is made recursively for more segments + */ + $scope.get_data = function(segment, query_id) { + if (DEBUG) { console.log('get data start.'); } + if (_.isUndefined(segment)) { + segment = 0; + } + delete $scope.panel.error; + + // Make sure we have everything for the request to complete + if(dashboard.indices.length === 0) { + return; + } + var _range = $scope.get_time_range(); + var _interval = $scope.get_interval(_range); + + if ($scope.panel.auto_int) { + $scope.panel.interval = kbn.secondsToHms( + kbn.calculate_interval(_range.from,_range.to,$scope.panel.resolution,0)/1000); + } + + $scope.panelMeta.loading = true; + + // Solr + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + var request = $scope.sjs.Request().indices(dashboard.indices[segment]); + // $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + if (DEBUG) { console.log($scope.panel.fields); } + + $scope.panel.queries.query = ""; + // Build the query + _.each($scope.panel.queries.ids, function(id) { + var query = $scope.sjs.FilteredQuery( + querySrv.getEjsObj(id), + filterSrv.getBoolFilter(filterSrv.ids) + ); + + var facet = $scope.sjs.DateHistogramFacet(id); + + }); + + if(_.isNull($scope.panel.value_field)) { + $scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified"; + return; + } + + + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + } + + var time_field = filterSrv.getTimeField(); + var start_time = filterSrv.getStartTime(); + var end_time = filterSrv.getEndTime(); + + $scope.panel.start_time = start_time; + $scope.panel.end_time = end_time; + + // facet.range.end does NOT accept * as a value, need to convert it to NOW + if (end_time === '*') { + end_time = 'NOW'; + } + + var wt_json = '&wt=json'; + var metric_field = $scope.panel.metric_field; + var anomaly_th = $scope.panel.anomaly_th; + var sort_field = '&sort='+'start_timestamp_l'+'%20asc'; + var rows_limit = '&rows='+$scope.panel.max_rows; + var facet = ''; + var fl = ''; + fq = fq + '&fq=anomaly_f:[' + anomaly_th + '%20TO%20*]'; + fq = fq + '&fq=result_s:ad'; + var mypromises = []; + var arr_id = []; + var index = 0; + if (_.isUndefined($routeParams.adValue)) { + } else { + $scope.panel.ad_name = $routeParams.adValue; + } + + _.defaults(dashboard.current,{anomaly_name:''}); + dashboard.current.anomaly_name = $scope.panel.ad_name; + var temp_fq = fq + '&fq=ad_name_s:'+$scope.panel.ad_name; + var temp_q = 'q=*:*' + wt_json + rows_limit + temp_fq + facet + fl + sort_field; + if (DEBUG) console.log(temp_q); + $scope.panel.queries.query += temp_q + "\n"; + if ($scope.panel.queries.custom !== null) { + request = request.setQuery(temp_q + $scope.panel.queries.custom); + } else { + request = request.setQuery(temp_q); + } + mypromises.push(request.doSearch()); + arr_id.push(0); + + $scope.data = []; + if (dashboard.current.services.query.ids.length >= 1) { + $q.all(mypromises).then(function(results) { + $scope.panelMeta.loading = false; + // Convert facet ids to numbers + // var facetIds = _.map(_.keys(results.facets),function(k){return parseInt(k, 10);}); + //var facetIds = [0]; // Need to fix this + + // Make sure we're still on the same query/queries + // TODO: We probably DON'T NEED THIS unless we have to support multiple queries in query module. + // if ($scope.query_id === query_id && _.difference(facetIds, $scope.panel.queries.ids).length === 0) { + var i = 0, + time_series, + hits; + + _.each(arr_id, function(id,index) { + // Check for error and abort if found + if (!(_.isUndefined(results[index].error))) { + $scope.panel.error = $scope.parse_error(results[index].error.msg); + return; + } + // we need to initialize the data variable on the first run, + // and when we are working on the first segment of the data. + if (_.isUndefined($scope.data[i]) || segment === 0) { + time_series = new timeSeries.ZeroFilled({ + interval: _interval, + start_date: _range && _range.from, + end_date: _range && _range.to, + fill_style: 'minimal' + }); + hits = 0; + } else { + time_series = $scope.data[i].time_series; + hits = 0; + $scope.hits = 0; + } + var entry_time, entries, entry_value; + $scope.data[i] = results[index].response.docs; + i++; + }); + + // Tell the histogram directive to render. + $scope.$emit('render'); + }); + } + }; + }); + + module.directive('adChart', function(querySrv,dashboard,filterSrv) { + return { + restrict: 'A', + link: function(scope, elem) { + var myChart; + // Receive render events + scope.$on('render',function(){ + render_panel(); + }); + + // Re-render if the window is resized + angular.element(window).bind('resize', function(){ + render_panel(); + }); + + // Function for rendering panel + function render_panel() { + var plot, chartData; + var colors = []; + + // IE doesn't work without this + elem.css({height:scope.panel.height||scope.row.height}); + + // Make a clone we can operate on. + + chartData = _.clone(scope.data); + chartData = scope.panel.missing ? chartData : + _.without(chartData,_.findWhere(chartData,{meta:'missing'})); + chartData = scope.panel.other ? chartData : + _.without(chartData,_.findWhere(chartData,{meta:'other'})); + + var heatmap_id = scope.$id; + require(['echarts'], function(ec){ + var echarts = ec; + if(myChart){ + myChart.dispose(); + } + var mertic = scope.panel.metric_field; + var labelcolor = false; + if (dashboard.current.style === 'dark'){ + labelcolor = true; + } + var cut_number = scope.panel.cut_number + 1; + myChart = echarts.init(document.getElementById(heatmap_id)); + var start_time = Date.parse(new Date(scope.get_time_range()['from'])); + var end_time = Date.parse(new Date(scope.get_time_range()['to'])); + var step = (end_time-start_time)/cut_number+1; + var ad_name = scope.panel.ad_name; + var dates = []; + var timestamps = []; + if (DEBUG) {console.log(scope.get_time_range());} + if (DEBUG) {console.log(start_time);} + + var data = []; + for (var timestamp = start_time; timestamp <= end_time; timestamp += step) { + timestamps.push(timestamp); + dates.push( + echarts.format.formatTime('yyyy/MM/dd hh:mm:ss', timestamp) + ); + data.push([]); + } + if (DEBUG) { console.log(ad_name); } + if (DEBUG) {console.log(chartData); } + chartData.map(function (anomalys) { + anomalys.map(function (anomaly) { + var date_index = Math.floor((anomaly['start_timestamp_l'] - start_time) / step); + if (date_index >= 0 && date_index < dates.length) { + var anomaly_date = echarts.format.formatTime('yyyy/MM/dd hh:mm:ss', anomaly['start_timestamp_l']); + var metric_value = anomaly.value_f; + var anomaly_value = anomaly.anomaly_f; + var from_timestamp = timestamps[date_index]; + var to_timestamp = timestamps[date_index]+step; + var solr_reader_url = anomaly.solr_reader_url_s; + var solr_writer_url = anomaly.solr_writer_url_s; + var stats_facet = anomaly.stats_facet_s; + var facet_name = anomaly.facet_name_s; + data[date_index].push({ + date_index: date_index, + anomaly_date: dates[date_index], + anomaly_value: anomaly_value, + metric_value: metric_value, + from_timestamp: from_timestamp, + to_timestamp: to_timestamp, + solr_reader_url : solr_reader_url, + solr_writer_url : solr_writer_url, + stats_facet : stats_facet, + facet_name : facet_name + }); + } + }); + }); + var show_data = []; + var max_num = 0; + for (var date_index = 0; date_index < dates.length; date_index++) { + if (data[date_index].length > 0) { + show_data.push([date_index,0,data[date_index].length]); + } + if (data[date_index].length > max_num) { + max_num = data[date_index].length; + } + } + if (DEBUG) { console.log(data); } + if (DEBUG) { console.log(max_num); } + var option = { + tooltip: { + show: false + }, + animation: false, + grid: { + height: '50%', + y: '10%' + }, + xAxis: { + type: 'category', + data: dates, + splitArea: { + show: true + }, + axisLine:{ + lineStyle:{ + color:'#aaaaaa', + width:1 + } + } + }, + yAxis: { + type: 'category', + data: [ad_name], + splitArea: { + show: true + }, + axisLine:{ + lineStyle:{ + color:'#aaaaaa', + width:1 + } + } + }, + visualMap: { + min: 0, + max: max_num, + calculable: true, + orient: 'horizontal', + left: 'center', + bottom: '15%', + show: false + }, + series: [{ + name: 'anomaly', + type: 'heatmap', + data: show_data, + label: { + normal: { + show: true + } + } + }] + }; + + myChart.setOption(option); + + myChart.on('click', function (params) { + if (DEBUG) { console.log(params); } + if (DEBUG) { console.log(data); } + var anomaly_th = scope.panel.anomaly_th; + var x = params.data[0]; + var from_timestamp = data[x][0].from_timestamp; + var to_timestamp = data[x][0].to_timestamp; + if (DEBUG) { console.log(from_timestamp + " " + to_timestamp);} + var fq = 'fq=start_timestamp_l:[' + Math.floor(from_timestamp) + '%20TO%20' + Math.floor(to_timestamp)+']'; + fq = fq + '&fq=ad_name_s:' + ad_name; + var anomaly_fq = fq + '&fq=anomaly_f:[' + anomaly_th + '%20TO%20*]'; + if (DEBUG) { console.log(fq); } + _.defaults(dashboard.current,{anomaly_fq:''}); + _.defaults(dashboard.current,{anomaly_name:''}); + _.defaults(dashboard.current,{anomaly_solr_reader_url:''}); + _.defaults(dashboard.current,{anomaly_stats_facet:''}); + _.defaults(dashboard.current,{anomaly_facet_name:''}); + _.defaults(dashboard.current,{fq:''}); + dashboard.current.anomaly_fq = anomaly_fq; + dashboard.current.fq = fq; + dashboard.current.anomaly_name = ad_name; + dashboard.current.anomaly_solr_reader_url = data[x][0].anomaly_solr_reader_url; + dashboard.current.anomaly_stats_facet = data[x][0].anomaly_stats_facet; + dashboard.current.anomaly_facet_name = data[x][0].anomaly_facet_name; + /* filterSrv.set({ + type : 'time', + from : moment.utc(Number(from_timestamp)).toDate(), + to : moment.utc(Number(to_timestamp)).toDate(), + field : filterSrv.getTimeField() + }); */ + dashboard.refresh(); + }); + }); + } + } + }; + }); + + +}); diff --git a/src/app/panels/ad/timeSeries.js b/src/app/panels/ad/timeSeries.js new file mode 100644 index 000000000..722768e22 --- /dev/null +++ b/src/app/panels/ad/timeSeries.js @@ -0,0 +1,178 @@ +define([ + 'underscore', + './interval' +], +function (_, Interval) { + 'use strict'; + + var ts = {}; + + // map compatable parseInt + function base10Int(val) { + return parseInt(val, 10); + } + + // trim the ms off of a time, but return it with empty ms. + function getDatesTime(date) { + return Math.floor(date.getTime() / 1000)*1000; + } + /** + * Certain graphs require 0 entries to be specified for them to render + * properly (like the line graph). So with this we will caluclate all of + * the expected time measurements, and fill the missing ones in with 0 + * @param {object} opts An object specifying some/all of the options + * + * OPTIONS: + * @opt {string} interval The interval notion describing the expected spacing between + * each data point. + * @opt {date} start_date (optional) The start point for the time series, setting this and the + * end_date will ensure that the series streches to resemble the entire + * expected result + * @opt {date} end_date (optional) The end point for the time series, see start_date + * @opt {string} fill_style Either "minimal", or "all" describing the strategy used to zero-fill + * the series. + */ + ts.ZeroFilled = function (opts) { + opts = _.defaults(opts, { + interval: '10m', + start_date: null, + end_date: null, + fill_style: 'minimal' + }); + + // the expected differenece between readings. + this.interval = new Interval(opts.interval); + + // will keep all values here, keyed by their time + this._data = {}; + this.start_time = opts.start_date && getDatesTime(opts.start_date); + this.end_time = opts.end_date && getDatesTime(opts.end_date); + this.opts = opts; + }; + + /** + * Add a row + * @param {int} time The time for the value, in + * @param {any} value The value at this time + */ + ts.ZeroFilled.prototype.addValue = function (time, value) { + if (time instanceof Date) { + time = getDatesTime(time); + } else { + time = base10Int(time); + } + if (!isNaN(time)) { + this._data[time] = (_.isUndefined(value) ? 0 : value); + } + this._cached_times = null; + }; + + /** + * Get an array of the times that have been explicitly set in the series + * @param {array} include (optional) list of timestamps to include in the response + * @return {array} An array of integer times. + */ + ts.ZeroFilled.prototype.getOrderedTimes = function (include) { + var times = _.map(_.keys(this._data), base10Int); + if (_.isArray(include)) { + times = times.concat(include); + } + return _.uniq(times.sort(function (a, b) { + // decending numeric sort + return a - b; + }), true); + }; + + /** + * return the rows in the format: + * [ [time, value], [time, value], ... ] + * + * Heavy lifting is done by _get(Min|All)FlotPairs() + * @param {array} required_times An array of timestamps that must be in the resulting pairs + * @return {array} + */ + ts.ZeroFilled.prototype.getFlotPairs = function (required_times) { + var times = this.getOrderedTimes(required_times), + strategy, + pairs; + + if(this.opts.fill_style === 'all') { + strategy = this._getAllFlotPairs; + } else { + strategy = this._getMinFlotPairs; + } + + pairs = _.reduce( + times, // what + strategy, // how + [], // where + this // context + ); + + // if the first or last pair is inside either the start or end time, + // add those times to the series with null values so the graph will stretch to contain them. + if (this.start_time && (pairs.length === 0 || pairs[0][0] > this.start_time)) { + pairs.unshift([this.start_time, null]); + } + if (this.end_time && (pairs.length === 0 || pairs[pairs.length - 1][0] < this.end_time)) { + pairs.push([this.end_time, null]); + } + + return pairs; + }; + + /** + * ** called as a reduce stragegy in getFlotPairs() ** + * Fill zero's on either side of the current time, unless there is already a measurement there or + * we are looking at an edge. + * @return {array} An array of points to plot with flot + */ + ts.ZeroFilled.prototype._getMinFlotPairs = function (result, time, i, times) { + var next, expected_next, prev, expected_prev; + + // check for previous measurement + if (i > 0) { + prev = times[i - 1]; + expected_prev = this.interval.before(time); + if (prev < expected_prev) { + result.push([expected_prev, 0]); + } + } + + // add the current time + result.push([ time, this._data[time] || 0 ]); + + // check for next measurement + if (times.length > i) { + next = times[i + 1]; + expected_next = this.interval.after(time); + if (next > expected_next) { + result.push([expected_next, 0]); + } + } + + return result; + }; + + /** + * ** called as a reduce stragegy in getFlotPairs() ** + * Fill zero's to the right of each time, until the next measurement is reached or we are at the + * last measurement + * @return {array} An array of points to plot with flot + */ + ts.ZeroFilled.prototype._getAllFlotPairs = function (result, time, i, times) { + var next, expected_next; + + result.push([ times[i], this._data[times[i]] || 0 ]); + next = times[i + 1]; + expected_next = this.interval.after(time); + for(; times.length > i && next > expected_next; expected_next = this.interval.after(expected_next)) { + result.push([expected_next, 0]); + } + + return result; + }; + + + return ts; +}); \ No newline at end of file diff --git a/src/app/panels/adDistribution/editor.html b/src/app/panels/adDistribution/editor.html new file mode 100644 index 000000000..d09082158 --- /dev/null +++ b/src/app/panels/adDistribution/editor.html @@ -0,0 +1,7 @@ +
Tooltip Settings
+
+
+ + +
+
\ No newline at end of file diff --git a/src/app/panels/adDistribution/interval.js b/src/app/panels/adDistribution/interval.js new file mode 100644 index 000000000..673371fcf --- /dev/null +++ b/src/app/panels/adDistribution/interval.js @@ -0,0 +1,57 @@ +define([ + 'kbn' +], +function (kbn) { + 'use strict'; + + /** + * manages the interval logic + * @param {[type]} interval_string An interval string in the format '1m', '1y', etc + */ + function Interval(interval_string) { + this.string = interval_string; + + var info = kbn.describe_interval(interval_string); + this.type = info.type; + this.ms = info.sec * 1000 * info.count; + + // does the length of the interval change based on the current time? + if (this.type === 'y' || this.type === 'M') { + // we will just modify this time object rather that create a new one constantly + this.get = this.get_complex; + this.date = new Date(0); + } else { + this.get = this.get_simple; + } + } + + Interval.prototype = { + toString: function () { + return this.string; + }, + after: function(current_ms) { + return this.get(current_ms, 1); + }, + before: function (current_ms) { + return this.get(current_ms, -1); + }, + get_complex: function (current, delta) { + this.date.setTime(current); + switch(this.type) { + case 'M': + this.date.setUTCMonth(this.date.getUTCMonth() + delta); + break; + case 'y': + this.date.setUTCFullYear(this.date.getUTCFullYear() + delta); + break; + } + return this.date.getTime(); + }, + get_simple: function (current, delta) { + return current + (delta * this.ms); + } + }; + + return Interval; + +}); \ No newline at end of file diff --git a/src/app/panels/adDistribution/module.html b/src/app/panels/adDistribution/module.html new file mode 100644 index 000000000..b7be420f9 --- /dev/null +++ b/src/app/panels/adDistribution/module.html @@ -0,0 +1,48 @@ +
+ + + + + + + +
+
\ No newline at end of file diff --git a/src/app/panels/adDistribution/module.js b/src/app/panels/adDistribution/module.js new file mode 100644 index 000000000..40dfccf5e --- /dev/null +++ b/src/app/panels/adDistribution/module.js @@ -0,0 +1,403 @@ +/* + + ## Anomaly Detection Distribution + + ### Parameters + * auto_int :: Auto calculate data point interval? + * resolution :: If auto_int is enables, shoot for this many data points, rounding to + sane intervals + * interval :: Datapoint interval in elasticsearch date math format (eg 1d, 1w, 1y, 5y) + * fill :: Only applies to line charts. Level of area shading from 0-10 + * linewidth :: Only applies to line charts. How thick the line should be in pixels + While the editor only exposes 0-10, this can be any numeric value. + Set to 0 and you'll get something like a scatter plot + * timezone :: This isn't totally functional yet. Currently only supports browser and utc. + browser will adjust the x-axis labels to match the timezone of the user's + browser + * spyable :: Dislay the 'eye' icon that show the last elasticsearch query + * zoomlinks :: Show the zoom links? + * bars :: Show bars in the chart + * stack :: Stack multiple queries. This generally a crappy way to represent things. + You probably should just use a line chart without stacking + * points :: Should circles at the data points on the chart + * lines :: Line chart? Sweet. + * legend :: Show the legend? + * x-axis :: Show x-axis labels and grid lines + * y-axis :: Show y-axis labels and grid lines + * interactive :: Allow drag to select time range + +*/ +define([ + 'angular', + 'app', + 'jquery', + 'underscore', + 'kbn', + 'moment', + './timeSeries' +], +function (angular, app, $, _, kbn, moment, timeSeries) { + 'use strict'; + var module = angular.module('kibana.panels.adDistribution', []); + app.useModule(module); + + var DEBUG = false; + console.log('DEBUG : ' + DEBUG); + module.controller('adDistribution', function($scope, $q, $http, querySrv, dashboard, filterSrv, alertSrv) { + $scope.panelMeta = { + modals : [ + { + description: "Inspect", + icon: "icon-info-sign", + partial: "app/partials/inspector.html", + show: $scope.panel.spyable + } + ], + editorTabs : [ + { + title:'Queries', + src:'app/partials/querySelect.html' + } + ], + status : "Stable", + description : "A bucketed time series chart of the current query, including all applied time and non-time filters, when used in count mode. Uses Solr’s facet.range query parameters. In values mode, it plots the value of a specific field over time, and allows the user to group field values by a second field." + }; + + // Set and populate defaults + var _d = { + mode : 'value', + queries : { + mode : 'all', + ids : [], + query : '*:*', + custom : '' + }, + max_rows : 1000, // maximum number of rows returned from Solr (also use this for group.limit to simplify UI setting) + reverse : 0, + group_field : null, + auto_int : true, + total_first : '%', + fontsize : 20, + field_color : '#209bf8', + resolution : 100, + value_sort : 'rs_timestamp', + interval : '5m', + intervals : ['auto','1s','1m','5m','10m','30m','1h','3h','12h','1d','1w','1M','1y'], + fill : 0, + linewidth : 3, + chart : 'stacking', + chartColors : ['#209bf8', '#f4d352','#ccf452','#8cf452','#3cee2b','#f467d8','#2fd7ee'], + timezone : 'browser', // browser, utc or a standard timezone + spyable : true, + zoomlinks : true, + bars : true, + stack : true, + label : true, + points : false, + lines : false, + lines_smooth: false, // Enable 'smooth line' mode by removing zero values from the plot. + legend : true, + 'x-axis' : true, + 'y-axis' : true, + percentage : false, + interactive : true, + options : true, + show_queries: true, + tooltip : { + value_type: 'cumulative', + query_as_alias: false + }, + jobid : '', + job_status: 'Ready', + fields : [] + }; + + _.defaults($scope.panel,_d); + + $scope.init = function() { + // Hide view options by default + if (DEBUG) console.log('init'); + $scope.options = false; + $scope.$on('refresh',function(){ + $scope.get_data(); + }); + + $scope.get_data(); + + }; + + $scope.set_interval = function(interval) { + if(interval !== 'auto') { + $scope.panel.auto_int = false; + $scope.panel.interval = interval; + } else { + $scope.panel.auto_int = true; + } + }; + + $scope.interval_label = function(interval) { + return $scope.panel.auto_int && interval === $scope.panel.interval ? interval+" (auto)" : interval; + }; + + $scope.set_refresh = function (state) { + $scope.refresh = state; + // if 'count' mode is selected, set decimal_points to zero automatically. + if ($scope.panel.mode === 'count') { + $scope.panel.decimal_points = 0; + } + $scope.get_data(); + }; + $scope.toggle_field = function(field) { + if (_.indexOf($scope.panel.fields, field) > -1) { + $scope.panel.fields = _.without($scope.panel.fields, field); + } else { + $scope.panel.fields.push(field); + } + }; + /** + * The time range effecting the panel + * @return {[type]} [description] + */ + $scope.get_time_range = function () { + var range = $scope.range = filterSrv.timeRange('min'); + return range; + }; + + $scope.get_interval = function () { + var interval = $scope.panel.interval, + range; + if ($scope.panel.auto_int) { + range = $scope.get_time_range(); + if (range) { + interval = kbn.secondsToHms( + kbn.calculate_interval(range.from, range.to, $scope.panel.resolution, 0) / 1000 + ); + } + } + $scope.panel.interval = interval || '10m'; + return $scope.panel.interval; + }; + + + $scope.build_query = function(filetype, isForExport) { + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + } + if (dashboard.current.fq) { + fq = fq + '&' + dashboard.current.fq; + } + var wt_json = '&wt=' + filetype; + var rows_limit = isForExport ? '&rows=0' : ''; // for terms, we do not need the actual response doc, so set rows=0 + var facet = ''; + { + // stats does not support something like facet.limit, so we have to sort and limit the results manually. + facet = '&facet=on' + '&facet.range=anomaly_f' + '&facet.range.start=0.0' + '&facet.range.end=1.0' + '&facet.range.gap=0.1'; + } + return querySrv.getORquery() + wt_json + rows_limit + fq + facet + ($scope.panel.queries.custom !== null ? $scope.panel.queries.custom : ''); + }; + + /** + * Fetch the data for a chunk of a queries results. Multiple segments occur when several indicies + * need to be consulted (like timestamped logstash indicies) + * + * The results of this function are stored on the scope's data property. This property will be an + * array of objects with the properties info, time_series, and hits. These objects are used in the + * render_panel function to create the historgram. + * + * !!! Solr does not need to fetch the data in chunk because it uses a facet search and retrieve + * !!! all events from a single query. + * + * @param {number} segment The segment count, (0 based) + * @param {number} query_id The id of the query, generated on the first run and passed back when + * this call is made recursively for more segments + */ + $scope.get_data = function(segment, query_id) { + if (DEBUG) console.log('get data start.'); + if (dashboard.indices.length === 0) { + return; + } + + delete $scope.panel.error; + $scope.panelMeta.loading = true; + var request, results; + + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + request = $scope.sjs.Request().indices(dashboard.indices); + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + + // Populate the inspector panel + $scope.inspector = angular.toJson(JSON.parse(request.toString()), true); + + if (DEBUG) console.log($scope.panel.stats_field); + + var query = this.build_query('json', false); + if (DEBUG) console.log(query); + // Set the panel's query + $scope.panel.queries.query = query; + + request.setQuery(query); + + results = request.doSearch(); + results.then(function (results) { + // Check for error and abort if found + if (!(_.isUndefined(results.error))) { + $scope.panel.error = $scope.parse_error(results.error.msg); + $scope.data = []; + $scope.panelMeta.loading = false; + $scope.$emit('render'); + return; + } + + // Function for validating HTML color by assign it to a dummy
+ // and let the browser do the work of validation. + var isValidHTMLColor = function (color) { + // clear attr first, before comparison + $('#colorTest').removeAttr('style'); + var valid = $('#colorTest').css('color'); + $('#colorTest').css('color', color); + + if (valid === $('#colorTest').css('color')) { + return false; + } else { + return true; + } + }; + + // Function for customizing chart color by using field values as colors. + var addSliceColor = function (slice, color) { + if ($scope.panel.useColorFromField && isValidHTMLColor(color)) { + slice.color = color; + } + return slice; + }; + + var sum = 0; + var k = 0; + var missing = 0; + $scope.panelMeta.loading = false; + $scope.hits = results.response.numFound; + $scope.data = []; + + { + // In stats mode, set y-axis min to null so jquery.flot will set the scale automatically. + $scope.yaxis_min = null; + if (DEBUG) console.log(results.facet_counts.facet_ranges.anomaly_f.counts); + _.each(results.facet_counts.facet_ranges.anomaly_f.counts, function (facet_obj) { + k = k + 1; + if (k%2 === 0) { + $scope.data.push(facet_obj); + } + }); + if (DEBUG) console.log($scope.data); + } + $scope.$emit('render'); + }); + }; + }); + + module.directive('distributionChart', function(querySrv,dashboard,filterSrv) { + return { + restrict: 'A', + link: function(scope, elem) { + var myChart; + // Receive render events + scope.$on('render',function(){ + render_panel(); + }); + + // Re-render if the window is resized + angular.element(window).bind('resize', function(){ + render_panel(); + }); + + // Function for rendering panel + function render_panel() { + var plot, chartData; + var colors = []; + + // IE doesn't work without this + elem.css({height:scope.panel.height||scope.row.height}); + + // Make a clone we can operate on. + + chartData = _.clone(scope.data); + chartData = scope.panel.missing ? chartData : + _.without(chartData,_.findWhere(chartData,{meta:'missing'})); + chartData = scope.panel.other ? chartData : + _.without(chartData,_.findWhere(chartData,{meta:'other'})); + + var distribution_id = scope.$id; + require(['echarts'], function(ec){ + var echarts = ec; + if(myChart){ + myChart.dispose(); + } + myChart = echarts.init(document.getElementById(distribution_id)); + var option = { + title : { + text: '异常分值分布情况', + x:'center', + textStyle: { + fontWeight: 'bolder', + color: '#aaa' // 主标题文字颜色 + }, + + }, + tooltip : { + trigger: 'item', + formatter: "异常分值在{b}之间的数é‡ä¸º: {c} ({d}%)" + }, + legend: { + x : 'center', + y : 'bottom', + data:['[0.0 TO 0.1]','[0.1 TO 0.2]','[0.2 TO 0.3]','[0.3 TO 0.4]', + '[0.4 TO 0.5]','[0.5 TO 0.6]','[0.6 TO 0.7]','[0.7 TO 0.8]', + '[0.8 TO 0.9]', '[0.9 TO 1.0]'] + }, + toolbox: { + show : true, + feature : { + mark : {show: true}, + dataView : {show: true, readOnly: false}, + magicType : { + show: true, + type: ['pie', 'funnel'] + }, + restore : {show: true}, + saveAsImage : {show: true} + } + }, + calculable : true, + series : [ + { + name:'异常分布', + type:'pie', + radius : [30, 110], + roseType : 'area', + data:[ + {value:scope.data[0], name:'[0.0 TO 0.1]'}, + {value:scope.data[1], name:'[0.1 TO 0.2]'}, + {value:scope.data[2], name:'[0.2 TO 0.3]'}, + {value:scope.data[3], name:'[0.3 TO 0.4]'}, + {value:scope.data[4], name:'[0.4 TO 0.5]'}, + {value:scope.data[5], name:'[0.5 TO 0.6]'}, + {value:scope.data[6], name:'[0.6 TO 0.7]'}, + {value:scope.data[7], name:'[0.7 TO 0.8]'}, + {value:scope.data[8], name:'[0.8 TO 0.9]'}, + {value:scope.data[9], name:'[0.9 TO 1.0]'}, + ] + } + ] + }; + myChart.setOption(option); + }); + } + } + }; + }); + + +}); diff --git a/src/app/panels/adDistribution/timeSeries.js b/src/app/panels/adDistribution/timeSeries.js new file mode 100644 index 000000000..722768e22 --- /dev/null +++ b/src/app/panels/adDistribution/timeSeries.js @@ -0,0 +1,178 @@ +define([ + 'underscore', + './interval' +], +function (_, Interval) { + 'use strict'; + + var ts = {}; + + // map compatable parseInt + function base10Int(val) { + return parseInt(val, 10); + } + + // trim the ms off of a time, but return it with empty ms. + function getDatesTime(date) { + return Math.floor(date.getTime() / 1000)*1000; + } + /** + * Certain graphs require 0 entries to be specified for them to render + * properly (like the line graph). So with this we will caluclate all of + * the expected time measurements, and fill the missing ones in with 0 + * @param {object} opts An object specifying some/all of the options + * + * OPTIONS: + * @opt {string} interval The interval notion describing the expected spacing between + * each data point. + * @opt {date} start_date (optional) The start point for the time series, setting this and the + * end_date will ensure that the series streches to resemble the entire + * expected result + * @opt {date} end_date (optional) The end point for the time series, see start_date + * @opt {string} fill_style Either "minimal", or "all" describing the strategy used to zero-fill + * the series. + */ + ts.ZeroFilled = function (opts) { + opts = _.defaults(opts, { + interval: '10m', + start_date: null, + end_date: null, + fill_style: 'minimal' + }); + + // the expected differenece between readings. + this.interval = new Interval(opts.interval); + + // will keep all values here, keyed by their time + this._data = {}; + this.start_time = opts.start_date && getDatesTime(opts.start_date); + this.end_time = opts.end_date && getDatesTime(opts.end_date); + this.opts = opts; + }; + + /** + * Add a row + * @param {int} time The time for the value, in + * @param {any} value The value at this time + */ + ts.ZeroFilled.prototype.addValue = function (time, value) { + if (time instanceof Date) { + time = getDatesTime(time); + } else { + time = base10Int(time); + } + if (!isNaN(time)) { + this._data[time] = (_.isUndefined(value) ? 0 : value); + } + this._cached_times = null; + }; + + /** + * Get an array of the times that have been explicitly set in the series + * @param {array} include (optional) list of timestamps to include in the response + * @return {array} An array of integer times. + */ + ts.ZeroFilled.prototype.getOrderedTimes = function (include) { + var times = _.map(_.keys(this._data), base10Int); + if (_.isArray(include)) { + times = times.concat(include); + } + return _.uniq(times.sort(function (a, b) { + // decending numeric sort + return a - b; + }), true); + }; + + /** + * return the rows in the format: + * [ [time, value], [time, value], ... ] + * + * Heavy lifting is done by _get(Min|All)FlotPairs() + * @param {array} required_times An array of timestamps that must be in the resulting pairs + * @return {array} + */ + ts.ZeroFilled.prototype.getFlotPairs = function (required_times) { + var times = this.getOrderedTimes(required_times), + strategy, + pairs; + + if(this.opts.fill_style === 'all') { + strategy = this._getAllFlotPairs; + } else { + strategy = this._getMinFlotPairs; + } + + pairs = _.reduce( + times, // what + strategy, // how + [], // where + this // context + ); + + // if the first or last pair is inside either the start or end time, + // add those times to the series with null values so the graph will stretch to contain them. + if (this.start_time && (pairs.length === 0 || pairs[0][0] > this.start_time)) { + pairs.unshift([this.start_time, null]); + } + if (this.end_time && (pairs.length === 0 || pairs[pairs.length - 1][0] < this.end_time)) { + pairs.push([this.end_time, null]); + } + + return pairs; + }; + + /** + * ** called as a reduce stragegy in getFlotPairs() ** + * Fill zero's on either side of the current time, unless there is already a measurement there or + * we are looking at an edge. + * @return {array} An array of points to plot with flot + */ + ts.ZeroFilled.prototype._getMinFlotPairs = function (result, time, i, times) { + var next, expected_next, prev, expected_prev; + + // check for previous measurement + if (i > 0) { + prev = times[i - 1]; + expected_prev = this.interval.before(time); + if (prev < expected_prev) { + result.push([expected_prev, 0]); + } + } + + // add the current time + result.push([ time, this._data[time] || 0 ]); + + // check for next measurement + if (times.length > i) { + next = times[i + 1]; + expected_next = this.interval.after(time); + if (next > expected_next) { + result.push([expected_next, 0]); + } + } + + return result; + }; + + /** + * ** called as a reduce stragegy in getFlotPairs() ** + * Fill zero's to the right of each time, until the next measurement is reached or we are at the + * last measurement + * @return {array} An array of points to plot with flot + */ + ts.ZeroFilled.prototype._getAllFlotPairs = function (result, time, i, times) { + var next, expected_next; + + result.push([ times[i], this._data[times[i]] || 0 ]); + next = times[i + 1]; + expected_next = this.interval.after(time); + for(; times.length > i && next > expected_next; expected_next = this.interval.after(expected_next)) { + result.push([expected_next, 0]); + } + + return result; + }; + + + return ts; +}); \ No newline at end of file diff --git a/src/app/panels/adFactor/editor.html b/src/app/panels/adFactor/editor.html new file mode 100644 index 000000000..c71ddb5db --- /dev/null +++ b/src/app/panels/adFactor/editor.html @@ -0,0 +1,14 @@ + +
Model Settings
+
+ + +
+
+
Tooltip Settings
+
+
+ + +
+
\ No newline at end of file diff --git a/src/app/panels/adFactor/interval.js b/src/app/panels/adFactor/interval.js new file mode 100644 index 000000000..673371fcf --- /dev/null +++ b/src/app/panels/adFactor/interval.js @@ -0,0 +1,57 @@ +define([ + 'kbn' +], +function (kbn) { + 'use strict'; + + /** + * manages the interval logic + * @param {[type]} interval_string An interval string in the format '1m', '1y', etc + */ + function Interval(interval_string) { + this.string = interval_string; + + var info = kbn.describe_interval(interval_string); + this.type = info.type; + this.ms = info.sec * 1000 * info.count; + + // does the length of the interval change based on the current time? + if (this.type === 'y' || this.type === 'M') { + // we will just modify this time object rather that create a new one constantly + this.get = this.get_complex; + this.date = new Date(0); + } else { + this.get = this.get_simple; + } + } + + Interval.prototype = { + toString: function () { + return this.string; + }, + after: function(current_ms) { + return this.get(current_ms, 1); + }, + before: function (current_ms) { + return this.get(current_ms, -1); + }, + get_complex: function (current, delta) { + this.date.setTime(current); + switch(this.type) { + case 'M': + this.date.setUTCMonth(this.date.getUTCMonth() + delta); + break; + case 'y': + this.date.setUTCFullYear(this.date.getUTCFullYear() + delta); + break; + } + return this.date.getTime(); + }, + get_simple: function (current, delta) { + return current + (delta * this.ms); + } + }; + + return Interval; + +}); \ No newline at end of file diff --git a/src/app/panels/adFactor/module.html b/src/app/panels/adFactor/module.html new file mode 100644 index 000000000..2be14ccfe --- /dev/null +++ b/src/app/panels/adFactor/module.html @@ -0,0 +1,48 @@ +
+ + + + + + + +
+
\ No newline at end of file diff --git a/src/app/panels/adFactor/module.js b/src/app/panels/adFactor/module.js new file mode 100644 index 000000000..7e99457bc --- /dev/null +++ b/src/app/panels/adFactor/module.js @@ -0,0 +1,573 @@ +/* + + ## Anomaly Detection Factor + + ### Parameters + * auto_int :: Auto calculate data point interval? + * resolution :: If auto_int is enables, shoot for this many data points, rounding to + sane intervals + * interval :: Datapoint interval in elasticsearch date math format (eg 1d, 1w, 1y, 5y) + * fill :: Only applies to line charts. Level of area shading from 0-10 + * linewidth :: Only applies to line charts. How thick the line should be in pixels + While the editor only exposes 0-10, this can be any numeric value. + Set to 0 and you'll get something like a scatter plot + * timezone :: This isn't totally functional yet. Currently only supports browser and utc. + browser will adjust the x-axis labels to match the timezone of the user's + browser + * spyable :: Dislay the 'eye' icon that show the last elasticsearch query + * zoomlinks :: Show the zoom links? + * bars :: Show bars in the chart + * stack :: Stack multiple queries. This generally a crappy way to represent things. + You probably should just use a line chart without stacking + * points :: Should circles at the data points on the chart + * lines :: Line chart? Sweet. + * legend :: Show the legend? + * x-axis :: Show x-axis labels and grid lines + * y-axis :: Show y-axis labels and grid lines + * interactive :: Allow drag to select time range + +*/ +define([ + 'angular', + 'app', + 'jquery', + 'underscore', + 'kbn', + 'moment', + './timeSeries' +], +function (angular, app, $, _, kbn, moment, timeSeries) { + 'use strict'; + var module = angular.module('kibana.panels.adLineChart', []); + app.useModule(module); + + var DEBUG = false; + console.log('DEBUG : ' + DEBUG); + module.controller('adLineChart', function($scope, $q, $http, querySrv, dashboard, filterSrv, alertSrv) { + $scope.panelMeta = { + modals : [ + { + description: "Inspect", + icon: "icon-info-sign", + partial: "app/partials/inspector.html", + show: $scope.panel.spyable + } + ], + editorTabs : [ + { + title:'Queries', + src:'app/partials/querySelect.html' + } + ], + status : "Stable", + description : "A bucketed time series chart of the current query, including all applied time and non-time filters, when used in count mode. Uses Solr’s facet.range query parameters. In values mode, it plots the value of a specific field over time, and allows the user to group field values by a second field." + }; + + // Set and populate defaults + var _d = { + mode : 'value', + queries : { + mode : 'all', + ids : [], + query : '*:*', + custom : '' + }, + max_rows : 1000, // maximum number of rows returned from Solr (also use this for group.limit to simplify UI setting) + reverse : 0, + group_field : null, + auto_int : true, + total_first : '%', + fontsize : 20, + field_color : '#209bf8', + resolution : 100, + value_sort : 'rs_timestamp', + interval : '5m', + intervals : ['auto','1s','1m','5m','10m','30m','1h','3h','12h','1d','1w','1M','1y'], + fill : 0, + linewidth : 3, + chart : 'stacking', + chartColors : ['#209bf8', '#f4d352','#ccf452','#8cf452','#3cee2b','#f467d8','#2fd7ee'], + timezone : 'browser', // browser, utc or a standard timezone + spyable : true, + zoomlinks : true, + bars : true, + stack : true, + label : true, + points : false, + lines : false, + lines_smooth: false, // Enable 'smooth line' mode by removing zero values from the plot. + legend : true, + 'x-axis' : true, + 'y-axis' : true, + percentage : false, + interactive : true, + options : true, + show_queries: true, + tooltip : { + value_type: 'cumulative', + query_as_alias: false + }, + jobid : '', + job_status: 'Ready', + fields : [] + }; + + _.defaults($scope.panel,_d); + + $scope.init = function() { + // Hide view options by default + if (DEBUG) console.log('init'); + $scope.options = false; + $scope.$on('refresh',function(){ + $scope.get_data(); + + }); + + $scope.get_data(); + }; + + $scope.set_interval = function(interval) { + if(interval !== 'auto') { + $scope.panel.auto_int = false; + $scope.panel.interval = interval; + } else { + $scope.panel.auto_int = true; + } + }; + + $scope.interval_label = function(interval) { + return $scope.panel.auto_int && interval === $scope.panel.interval ? interval+" (auto)" : interval; + }; + + $scope.set_refresh = function (state) { + $scope.refresh = state; + // if 'count' mode is selected, set decimal_points to zero automatically. + if ($scope.panel.mode === 'count') { + $scope.panel.decimal_points = 0; + } + $scope.get_data(); + }; + $scope.toggle_field = function(field) { + if (_.indexOf($scope.panel.fields, field) > -1) { + $scope.panel.fields = _.without($scope.panel.fields, field); + } else { + $scope.panel.fields.push(field); + } + }; + /** + * The time range effecting the panel + * @return {[type]} [description] + */ + $scope.get_time_range = function () { + var range = $scope.range = filterSrv.timeRange('min'); + return range; + }; + + $scope.get_interval = function () { + var interval = $scope.panel.interval, + range; + if ($scope.panel.auto_int) { + range = $scope.get_time_range(); + if (range) { + interval = kbn.secondsToHms( + kbn.calculate_interval(range.from, range.to, $scope.panel.resolution, 0) / 1000 + ); + } + } + $scope.panel.interval = interval || '10m'; + return $scope.panel.interval; + }; + + + $scope.build_query = function(filetype, isForExport) { + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + } + if (dashboard.current.anomaly_fq) { + fq = fq + '&' + dashboard.current.anomaly_fq; + } + var wt_json = '&wt=' + filetype; + var rows_limit = isForExport ? '&rows=0' : '&rows='+$scope.panel.max_rows; // for terms, we do not need the actual response doc, so set rows=0 + var facet = ''; + return querySrv.getORquery() + wt_json + rows_limit + fq + facet + ($scope.panel.queries.custom !== null ? $scope.panel.queries.custom : ''); + }; + + /** + * Fetch the data for a chunk of a queries results. Multiple segments occur when several indicies + * need to be consulted (like timestamped logstash indicies) + * + * The results of this function are stored on the scope's data property. This property will be an + * array of objects with the properties info, time_series, and hits. These objects are used in the + * render_panel function to create the historgram. + * + * !!! Solr does not need to fetch the data in chunk because it uses a facet search and retrieve + * !!! all events from a single query. + * + * @param {number} segment The segment count, (0 based) + * @param {number} query_id The id of the query, generated on the first run and passed back when + * this call is made recursively for more segments + */ + $scope.get_data = function(segment, query_id) { + if (DEBUG) console.log('get data start.'); + if (dashboard.indices.length === 0) { + return; + } + + delete $scope.panel.error; + $scope.panelMeta.loading = true; + var request, results; + + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + request = $scope.sjs.Request().indices(dashboard.indices); + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + + // Populate the inspector panel + $scope.inspector = angular.toJson(JSON.parse(request.toString()), true); + + if (DEBUG) console.log($scope.panel.stats_field); + + var query = this.build_query('json', false); + if (DEBUG) console.log(query); + // Set the panel's query + $scope.panel.queries.query = query; + + request.setQuery(query); + + results = request.doSearch(); + results.then(function (result) { + // Check for error and abort if found + if (!(_.isUndefined(result.error))) { + $scope.panel.error = $scope.parse_error(results.error.msg); + $scope.data = []; + $scope.panelMeta.loading = false; + $scope.$emit('render'); + return; + } + + // Function for validating HTML color by assign it to a dummy
+ // and let the browser do the work of validation. + var isValidHTMLColor = function (color) { + // clear attr first, before comparison + $('#colorTest').removeAttr('style'); + var valid = $('#colorTest').css('color'); + $('#colorTest').css('color', color); + + if (valid === $('#colorTest').css('color')) { + return false; + } else { + return true; + } + }; + + // Function for customizing chart color by using field values as colors. + var addSliceColor = function (slice, color) { + if ($scope.panel.useColorFromField && isValidHTMLColor(color)) { + slice.color = color; + } + return slice; + }; + + var sum = 0; + var k = 0; + var missing = 0; + $scope.panelMeta.loading = false; + $scope.data = [0, 0, 0]; + { + // In stats mode, set y-axis min to null so jquery.flot will set the scale automatically. + $scope.yaxis_min = null; + if (DEBUG) console.log(result.response.docs); + _.each(result.response.docs, function (doc_obj) { + var value = doc_obj.anomaly_factor_s; + if (value === 'Small') $scope.data[0] += 1; + else if (value === 'Large') $scope.data[2] += 1; + else $scope.data[1] += 1; + }); + if (DEBUG) console.log($scope.data); + $scope.$emit('render'); + } + }); + }; + }); + + module.directive('lineChart', function(querySrv,dashboard,filterSrv) { + return { + restrict: 'A', + link: function(scope, elem) { + var myChart; + // Receive render events + scope.$on('render',function(){ + render_panel(); + }); + + // Re-render if the window is resized + angular.element(window).bind('resize', function(){ + render_panel(); + }); + + // Function for rendering panel + function render_panel() { + var plot, chartData; + var colors = []; + + // IE doesn't work without this + elem.css({height: scope.panel.height || scope.row.height}); + + // Make a clone we can operate on. + + chartData = _.clone(scope.data); + chartData = scope.panel.missing ? chartData : + _.without(chartData, _.findWhere(chartData, {meta: 'missing'})); + chartData = scope.panel.other ? chartData : + _.without(chartData, _.findWhere(chartData, {meta: 'other'})); + + var factor_id = scope.$id; + require(['echarts'], function (ec) { + var echarts = ec; + if(myChart){ + myChart.dispose(); + } + myChart = echarts.init(document.getElementById(factor_id)); + + var option = { + backgroundColor: '#1b1b1b', + tooltip: { + formatter: "{a}
{c} {b}" + }, + toolbox: { + show: true, + feature: { + mark: {show: true}, + restore: {show: true}, + saveAsImage: {show: true} + } + }, + series: [ + { + name: '陌生波动数é‡', + type: 'gauge', + min: 0, + max: 20, + splitNumber: 10, + radius: '70%', + axisLine: { // åæ ‡è½´çº¿ + lineStyle: { // 属性lineStyleæŽ§åˆ¶çº¿æ¡æ ·å¼ + color: [[1.0, '#1e90ff']], + width: 3, + shadowColor: '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 10 + } + }, + axisLabel: { // åæ ‡è½´å°æ ‡è®° + textStyle: { // 属性lineStyleæŽ§åˆ¶çº¿æ¡æ ·å¼ + fontWeight: 'bolder', + color: '#fff', + shadowColor: '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 10 + } + }, + axisTick: { // åæ ‡è½´å°æ ‡è®° + length: 15, // 属性length控制线长 + lineStyle: { // 属性lineStyleæŽ§åˆ¶çº¿æ¡æ ·å¼ + color: 'auto', + shadowColor: '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 10 + } + }, + splitLine: { // 分隔线 + length: 25, // 属性length控制线长 + lineStyle: { // 属性lineStyle(详è§lineStyleï¼‰æŽ§åˆ¶çº¿æ¡æ ·å¼ + width: 3, + color: '#fff', + shadowColor: '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 10 + } + }, + pointer: { // 分隔线 + shadowColor: '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 5 + }, + title: { + textStyle: { // 其余属性默认使用全局文本样å¼ï¼Œè¯¦è§TEXTSTYLE + fontWeight: 'bolder', + fontSize: 20, + fontStyle: 'italic', + color: '#fff', + shadowColor: '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 10 + } + }, + detail: { + backgroundColor: 'rgba(30,144,255,0.8)', + borderWidth: 1, + borderColor: '#fff', + shadowColor: '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 5, + offsetCenter: [0, '50%'], // x, y,å•ä½px + textStyle: { // 其余属性默认使用全局文本样å¼ï¼Œè¯¦è§TEXTSTYLE + fontWeight: 'bolder', + color: '#fff' + } + }, + data: [{value: scope.data[1], name: 'Strange Fluctuation'}] + }, + { + name: 'è¿‡å°æ•°é‡', + type: 'gauge', + center: ['20%', '55%'], // 默认全局居中 + radius: '50%', + min: 0, + max: 10, + endAngle: 45, + splitNumber: 10, + axisLine: { // åæ ‡è½´çº¿ + lineStyle: { // 属性lineStyleæŽ§åˆ¶çº¿æ¡æ ·å¼ + color: [[1.0, 'lime']], + width: 2, + shadowColor: '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 10 + } + }, + axisLabel: { // åæ ‡è½´å°æ ‡è®° + textStyle: { // 属性lineStyleæŽ§åˆ¶çº¿æ¡æ ·å¼ + fontWeight: 'bolder', + color: '#fff', + shadowColor: '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 10 + } + }, + axisTick: { // åæ ‡è½´å°æ ‡è®° + length: 12, // 属性length控制线长 + lineStyle: { // 属性lineStyleæŽ§åˆ¶çº¿æ¡æ ·å¼ + color: 'auto', + shadowColor: '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 10 + } + }, + splitLine: { // 分隔线 + length: 20, // 属性length控制线长 + lineStyle: { // 属性lineStyle(详è§lineStyleï¼‰æŽ§åˆ¶çº¿æ¡æ ·å¼ + width: 3, + color: '#fff', + shadowColor: '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 10 + } + }, + pointer: { + width: 5, + shadowColor: '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 5 + }, + title: { + offsetCenter: [0, '-30%'], // x, y,å•ä½px + textStyle: { // 其余属性默认使用全局文本样å¼ï¼Œè¯¦è§TEXTSTYLE + fontWeight: 'bolder', + fontStyle: 'italic', + color: '#fff', + shadowColor: '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 10 + } + }, + detail: { + //backgroundColor: 'rgba(30,144,255,0.8)', + // borderWidth: 1, + borderColor: '#fff', + shadowColor: '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 5, + width: 80, + height: 30, + offsetCenter: [0, '20%'], // x, y,å•ä½px + textStyle: { // 其余属性默认使用全局文本样å¼ï¼Œè¯¦è§TEXTSTYLE + fontWeight: 'bolder', + color: '#fff' + } + }, + data: [{value: scope.data[0], name: 'Small Value'}] + }, + { + name: '过大数é‡', + type: 'gauge', + center: ['80%', '55%'], // 默认全局居中 + radius: '50%', + min: 0, + max: 10, + startAngle: 135, + endAngle: -45, + splitNumber: 10, + axisLine: { // åæ ‡è½´çº¿ + lineStyle: { // 属性lineStyleæŽ§åˆ¶çº¿æ¡æ ·å¼ + color: [[1, '#ff4500']], + width: 2, + shadowColor: '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 10 + } + }, + axisLabel: { // åæ ‡è½´å°æ ‡è®° + textStyle: { // 属性lineStyleæŽ§åˆ¶çº¿æ¡æ ·å¼ + fontWeight: 'bolder', + color: '#fff', + shadowColor: '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 10 + } + }, + axisTick: { // åæ ‡è½´å°æ ‡è®° + length: 12, // 属性length控制线长 + lineStyle: { // 属性lineStyleæŽ§åˆ¶çº¿æ¡æ ·å¼ + color: 'auto', + shadowColor: '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 10 + } + }, + splitLine: { // 分隔线 + length: 20, // 属性length控制线长 + lineStyle: { // 属性lineStyle(详è§lineStyleï¼‰æŽ§åˆ¶çº¿æ¡æ ·å¼ + width: 3, + color: '#fff', + shadowColor: '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 10 + } + }, + pointer: { + width: 5, + shadowColor: '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 5 + }, + title: { + offsetCenter: [0, '-30%'], // x, y,å•ä½px + textStyle: { // 其余属性默认使用全局文本样å¼ï¼Œè¯¦è§TEXTSTYLE + fontWeight: 'bolder', + fontStyle: 'italic', + color: '#fff', + shadowColor: '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 10 + } + }, + detail: { + //backgroundColor: 'rgba(30,144,255,0.8)', + // borderWidth: 1, + borderColor: '#fff', + shadowColor: '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 5, + width: 80, + height: 30, + offsetCenter: [0, '20%'], // x, y,å•ä½px + textStyle: { // 其余属性默认使用全局文本样å¼ï¼Œè¯¦è§TEXTSTYLE + fontWeight: 'bolder', + color: '#fff' + } + }, + data: [{value: scope.data[2], name: 'Large Value'}] + } + ] + }; + myChart.setOption(option); + }); + } + } + }; + }); + + +}); diff --git a/src/app/panels/adFactor/timeSeries.js b/src/app/panels/adFactor/timeSeries.js new file mode 100644 index 000000000..722768e22 --- /dev/null +++ b/src/app/panels/adFactor/timeSeries.js @@ -0,0 +1,178 @@ +define([ + 'underscore', + './interval' +], +function (_, Interval) { + 'use strict'; + + var ts = {}; + + // map compatable parseInt + function base10Int(val) { + return parseInt(val, 10); + } + + // trim the ms off of a time, but return it with empty ms. + function getDatesTime(date) { + return Math.floor(date.getTime() / 1000)*1000; + } + /** + * Certain graphs require 0 entries to be specified for them to render + * properly (like the line graph). So with this we will caluclate all of + * the expected time measurements, and fill the missing ones in with 0 + * @param {object} opts An object specifying some/all of the options + * + * OPTIONS: + * @opt {string} interval The interval notion describing the expected spacing between + * each data point. + * @opt {date} start_date (optional) The start point for the time series, setting this and the + * end_date will ensure that the series streches to resemble the entire + * expected result + * @opt {date} end_date (optional) The end point for the time series, see start_date + * @opt {string} fill_style Either "minimal", or "all" describing the strategy used to zero-fill + * the series. + */ + ts.ZeroFilled = function (opts) { + opts = _.defaults(opts, { + interval: '10m', + start_date: null, + end_date: null, + fill_style: 'minimal' + }); + + // the expected differenece between readings. + this.interval = new Interval(opts.interval); + + // will keep all values here, keyed by their time + this._data = {}; + this.start_time = opts.start_date && getDatesTime(opts.start_date); + this.end_time = opts.end_date && getDatesTime(opts.end_date); + this.opts = opts; + }; + + /** + * Add a row + * @param {int} time The time for the value, in + * @param {any} value The value at this time + */ + ts.ZeroFilled.prototype.addValue = function (time, value) { + if (time instanceof Date) { + time = getDatesTime(time); + } else { + time = base10Int(time); + } + if (!isNaN(time)) { + this._data[time] = (_.isUndefined(value) ? 0 : value); + } + this._cached_times = null; + }; + + /** + * Get an array of the times that have been explicitly set in the series + * @param {array} include (optional) list of timestamps to include in the response + * @return {array} An array of integer times. + */ + ts.ZeroFilled.prototype.getOrderedTimes = function (include) { + var times = _.map(_.keys(this._data), base10Int); + if (_.isArray(include)) { + times = times.concat(include); + } + return _.uniq(times.sort(function (a, b) { + // decending numeric sort + return a - b; + }), true); + }; + + /** + * return the rows in the format: + * [ [time, value], [time, value], ... ] + * + * Heavy lifting is done by _get(Min|All)FlotPairs() + * @param {array} required_times An array of timestamps that must be in the resulting pairs + * @return {array} + */ + ts.ZeroFilled.prototype.getFlotPairs = function (required_times) { + var times = this.getOrderedTimes(required_times), + strategy, + pairs; + + if(this.opts.fill_style === 'all') { + strategy = this._getAllFlotPairs; + } else { + strategy = this._getMinFlotPairs; + } + + pairs = _.reduce( + times, // what + strategy, // how + [], // where + this // context + ); + + // if the first or last pair is inside either the start or end time, + // add those times to the series with null values so the graph will stretch to contain them. + if (this.start_time && (pairs.length === 0 || pairs[0][0] > this.start_time)) { + pairs.unshift([this.start_time, null]); + } + if (this.end_time && (pairs.length === 0 || pairs[pairs.length - 1][0] < this.end_time)) { + pairs.push([this.end_time, null]); + } + + return pairs; + }; + + /** + * ** called as a reduce stragegy in getFlotPairs() ** + * Fill zero's on either side of the current time, unless there is already a measurement there or + * we are looking at an edge. + * @return {array} An array of points to plot with flot + */ + ts.ZeroFilled.prototype._getMinFlotPairs = function (result, time, i, times) { + var next, expected_next, prev, expected_prev; + + // check for previous measurement + if (i > 0) { + prev = times[i - 1]; + expected_prev = this.interval.before(time); + if (prev < expected_prev) { + result.push([expected_prev, 0]); + } + } + + // add the current time + result.push([ time, this._data[time] || 0 ]); + + // check for next measurement + if (times.length > i) { + next = times[i + 1]; + expected_next = this.interval.after(time); + if (next > expected_next) { + result.push([expected_next, 0]); + } + } + + return result; + }; + + /** + * ** called as a reduce stragegy in getFlotPairs() ** + * Fill zero's to the right of each time, until the next measurement is reached or we are at the + * last measurement + * @return {array} An array of points to plot with flot + */ + ts.ZeroFilled.prototype._getAllFlotPairs = function (result, time, i, times) { + var next, expected_next; + + result.push([ times[i], this._data[times[i]] || 0 ]); + next = times[i + 1]; + expected_next = this.interval.after(time); + for(; times.length > i && next > expected_next; expected_next = this.interval.after(expected_next)) { + result.push([expected_next, 0]); + } + + return result; + }; + + + return ts; +}); \ No newline at end of file diff --git a/src/app/panels/adIPStatistics/editor.html b/src/app/panels/adIPStatistics/editor.html new file mode 100644 index 000000000..cf3f995d7 --- /dev/null +++ b/src/app/panels/adIPStatistics/editor.html @@ -0,0 +1,6 @@ +
+
+ + +
+
\ No newline at end of file diff --git a/src/app/panels/adIPStatistics/module.html b/src/app/panels/adIPStatistics/module.html new file mode 100644 index 000000000..f4a868c20 --- /dev/null +++ b/src/app/panels/adIPStatistics/module.html @@ -0,0 +1,60 @@ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + +
异常检测 äº‹åŠ¡é“¾æŽ¥ å¼‚常数釠
+ +
{{term.name}}{{term.term}}{{term.count}}
+ + + +
+ +
\ No newline at end of file diff --git a/src/app/panels/adIPStatistics/module.js b/src/app/panels/adIPStatistics/module.js new file mode 100644 index 000000000..c82cd69c0 --- /dev/null +++ b/src/app/panels/adIPStatistics/module.js @@ -0,0 +1,463 @@ +/* + ## Terms + + ### Parameters + * style :: A hash of css styles + * size :: top N + * arrangement :: How should I arrange the query results? 'horizontal' or 'vertical' + * chart :: Show a chart? 'none', 'bar', 'pie' + * donut :: Only applies to 'pie' charts. Punches a hole in the chart for some reason + * tilt :: Only 'pie' charts. Janky 3D effect. Looks terrible 90% of the time. + * lables :: Only 'pie' charts. Labels on the pie? + */ +define([ + 'angular', + 'app', + 'underscore', + 'jquery', + 'kbn', + 'smart-table' + ], + function (angular, app, _, $, kbn) { + 'use strict'; + var DEBUG = true; + + var module = angular.module('kibana.panels.adDistribution', []); + app.useModule(module); + + module.controller('adDistribution', function($scope, $timeout, $filter, timer, querySrv, dashboard, filterSrv) { + $scope.panelMeta = { + exportfile: true, + editorTabs : [ + {title:'Queries', src:'app/partials/querySelect.html'} + ], + status : "Stable", + description : "Displays the results of a Solr facet as a pie chart, bar chart, or a table. Newly added functionality displays min/max/mean/sum of a stats field, faceted by the Solr facet field, again as a pie chart, bar chart or a table." + }; + + // Set and populate defaults + var _d = { + queries : { + mode : 'all', + ids : [], + query : '*:*', + custom : '' + }, + mode : 'count', // mode to tell which number will be used to plot the chart. + field : '', + stats_field : '', + decimal_points : 0, // The number of digits after the decimal point + exclude : [], + missing : false, + other : false, + size : 10000, + display:'block', + icon:"icon-caret-down", + sortBy : 'count', + threshold_first:3000, + threshold_second:5000, + order : 'descending', + style : { "font-size": '10pt'}, + fontsize:20, + linkage_id:'a', + donut : false, + tilt : false, + labels : true, + logAxis : false, + arrangement : 'horizontal', + chart : 'bar', + counter_pos : 'above', + exportSize : 10000, + lastColor : '', + spyable : true, + show_queries:true, + error : '', + chartColors : querySrv.colors, + refresh: { + enable: false, + interval: 2 + } + }; + _.defaults($scope.panel,_d); + + $scope.init = function () { + $scope.hits = 0; + //$scope.testMultivalued(); + + // Start refresh timer if enabled + if ($scope.panel.refresh.enable) { + $scope.set_timer($scope.panel.refresh.interval); + } + + $scope.$on('refresh',function(){ + $scope.get_data(); + }); + + $scope.get_data(); + }; + + $scope.get_time_range = function () { + var range = filterSrv.timeRange('min'); + return range; + }; + + $scope.testMultivalued = function() { + if($scope.panel.field && $scope.fields.typeList[$scope.panel.field] && $scope.fields.typeList[$scope.panel.field].schema.indexOf("M") > -1) { + $scope.panel.error = "Can't proceed with Multivalued field"; + return; + } + + if($scope.panel.stats_field && $scope.fields.typeList[$scope.panel.stats_field].schema.indexOf("M") > -1) { + $scope.panel.error = "Can't proceed with Multivalued field"; + return; + } + }; + $scope.display=function() { + if($scope.panel.display=='none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; + /** + * + * + * @param {String} filetype -'json', 'xml', 'csv' + */ + $scope.build_query = function(filetype, isForExport) { + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + } + if (dashboard.current.anomaly_fq) { + fq = fq + '&' + dashboard.current.anomaly_fq; + } + var wt_json = '&wt=' + filetype; + var rows_limit = isForExport ? '&rows=0' : ''; // for terms, we do not need the actual response doc, so set rows=0 + var facet = ''; + { + // stats does not support something like facet.limit, so we have to sort and limit the results manually. + facet = '&stats=true&stats.facet=facet_name_s' + '&stats.field=value_f' + '&facet.missing=true'; + } + + var exclude_length = $scope.panel.exclude.length; + var exclude_filter = ''; + if(exclude_length > 0){ + for (var i = 0; i < exclude_length; i++) { + if($scope.panel.exclude[i] !== "") { + exclude_filter += '&fq=-' + $scope.panel.field +":"+ $scope.panel.exclude[i]; + } + } + } + return querySrv.getORquery() + wt_json + rows_limit + fq + exclude_filter + facet + ($scope.panel.queries.custom !== null ? $scope.panel.queries.custom : ''); + }; + + $scope.exportfile = function(filetype) { + + var query = this.build_query(filetype, true); + + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + var request = $scope.sjs.Request().indices(dashboard.indices), + response; + + request.setQuery(query); + + response = request.doSearch(); + + // Populate scope when we have results + response.then(function(response) { + kbn.download_response(response, filetype, "terms"); + }); + }; + + $scope.set_timer = function(refresh_interval) { + $scope.panel.refresh.interval = refresh_interval; + if (_.isNumber($scope.panel.refresh.interval)) { + timer.cancel($scope.refresh_timer); + $scope.realtime(); + } else { + timer.cancel($scope.refresh_timer); + } + }; + + $scope.realtime = function() { + if ($scope.panel.refresh.enable) { + timer.cancel($scope.refresh_timer); + + $scope.refresh_timer = timer.register($timeout(function() { + $scope.realtime(); + $scope.get_data(); + }, $scope.panel.refresh.interval*1000)); + } else { + timer.cancel($scope.refresh_timer); + } + }; + + $scope.get_data = function() { + $scope.panel.mode = 'all'; + if(($scope.panel.linkage_id==dashboard.current.linkage_id)||dashboard.current.enable_linkage){ + // Make sure we have everything for the request to complete + if (dashboard.indices.length === 0) { + return; + } + + delete $scope.panel.error; + $scope.panelMeta.loading = true; + var request, results; + + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + request = $scope.sjs.Request().indices(dashboard.indices); + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + + // Populate the inspector panel + $scope.inspector = angular.toJson(JSON.parse(request.toString()), true); + + if (DEBUG) console.log($scope.panel.stats_field); + + var query = this.build_query('json', false); + + // Set the panel's query + $scope.panel.queries.query = query; + + request.setQuery(query); + if (DEBUG) console.log(query); + results = request.doSearch(); + // Populate scope when we have results + results.then(function (results) { + // Check for error and abort if found + if (!(_.isUndefined(results.error))) { + $scope.panel.error = $scope.parse_error(results.error.msg); + $scope.data = []; + $scope.panelMeta.loading = false; + $scope.$emit('render'); + return; + } + + // Function for validating HTML color by assign it to a dummy
+ // and let the browser do the work of validation. + var isValidHTMLColor = function (color) { + // clear attr first, before comparison + $('#colorTest').removeAttr('style'); + var valid = $('#colorTest').css('color'); + $('#colorTest').css('color', color); + + if (valid === $('#colorTest').css('color')) { + return false; + } else { + return true; + } + }; + + // Function for customizing chart color by using field values as colors. + var addSliceColor = function (slice, color) { + if ($scope.panel.useColorFromField && isValidHTMLColor(color)) { + slice.color = color; + } + return slice; + }; + + if (DEBUG) console.log(results); + var sum = 0; + var k = 0; + var missing = 0; + $scope.panelMeta.loading = false; + $scope.hits = results.response.numFound; + $scope.data = []; + + { + // In stats mode, set y-axis min to null so jquery.flot will set the scale automatically. + $scope.yaxis_min = null; + if (DEBUG) console.log(results.stats.stats_fields.value_f.facets.facet_name_s); + _.each(results.stats.stats_fields.value_f.facets.facet_name_s, function (stats_obj, facet_field) { + k = k + 1; + //var slice = {label: facet_field, data: [[k, stats_obj['mean'], stats_obj['count'], stats_obj['max'], stats_obj['min'], stats_obj['stddev'], facet_field]], actions: true}; + var term = facet_field; + if (term.length > 50) term = term.substring(0,40) + ' ...'; + if (term === '') { + term = '全部访问'; + } + var slice = {term: term, index: k, name: dashboard.current.anomaly_name, count: stats_obj['count'], max: stats_obj['max'], min: stats_obj['min'], stddev: stats_obj['stddev'], actions: true}; + $scope.data.push(slice); + }); + } + + + // Slice it according to panel.size, and then set the x-axis values with k. + // $scope.data = $scope.data.slice(0, $scope.panel.size); + + if ($scope.panel.field && $scope.fields.typeList[$scope.panel.field] && $scope.fields.typeList[$scope.panel.field].schema.indexOf("T") > -1) { + $scope.hits = sum; + } + /* + $scope.data.push({ + label: 'Missing field', + // data:[[k,results.facets.terms.missing]],meta:"missing",color:'#aaa',opacity:0}); + // TODO: Hard coded to 0 for now. Solr faceting does not provide 'missing' value. + data: [[k, missing]], meta: "missing", color: '#aaa', opacity: 0 + }); + $scope.data.push({ + label: 'Other values', + // data:[[k+1,results.facets.terms.other]],meta:"other",color:'#444'}); + // TODO: Hard coded to 0 for now. Solr faceting does not provide 'other' value. + data: [[k + 1, $scope.hits - sum]], meta: "other", color: '#444' + }); + */ + + $scope.$emit('render'); + + $scope.sortingOrder = 'term'; + $scope.reverse = false; + $scope.filteredItems = []; + $scope.groupedItems = []; + $scope.itemsPerPage = 10; + $scope.pagedItems = []; + $scope.currentPage = 0; + + // init the filtered items + var searchMatch = function (haystack, needle) { + if (!needle) { + return true; + } + var res = haystack.toLowerCase().indexOf(needle.toLowerCase()) !== -1; + return res; + }; + + $scope.search = function () { + $scope.filteredItems = $filter('filter')($scope.data, function (item) { + if (searchMatch(item.term, $scope.query)) { + return true; + } + return false; + }); + if ($scope.sortingOrder !== '') { + $scope.filteredItems = $filter('orderBy')($scope.filteredItems, $scope.sortingOrder, $scope.reverse); + } + $scope.currentPage = 0; + $scope.groupToPages(); + }; + + + // calculate page in place + $scope.groupToPages = function () { + $scope.pagedItems = []; + + for (var i = 0; i < $scope.filteredItems.length; i++) { + if (i % $scope.itemsPerPage === 0) { + $scope.pagedItems[Math.floor(i / $scope.itemsPerPage)] = [ $scope.filteredItems[i] ]; + } else { + $scope.pagedItems[Math.floor(i / $scope.itemsPerPage)].push($scope.filteredItems[i]); + } + } + }; + + $scope.prevPage = function () { + if ($scope.currentPage > 0) { + $scope.currentPage--; + } + }; + + $scope.nextPage = function () { + if ($scope.currentPage < $scope.pagedItems.length - 1) { + $scope.currentPage++; + } + }; + + $scope.setPage = function () { + $scope.currentPage = this.n; + }; + + // functions have been describe process the data for display + $scope.range = function (size,start, end) { + var ret = []; + + if (size < end) { + end = size; + if(size<$scope.gap){ + start = 0; + }else{ + start = size-$scope.gap; + } + + } + for (var i = start; i < end; i++) { + ret.push(i); + } + return ret; + }; + $scope.search(); + + $scope.sort_by = function(newSortingOrder) { + if (DEBUG) console.log($scope.sortingOrder + "\t" + newSortingOrder); + if ($scope.sortingOrder == newSortingOrder){ + $scope.reverse = !$scope.reverse; + if (DEBUG) console.log($scope.reverse); + $scope.filteredItems.reverse(); + } + else { + $scope.reverse = true; + $scope.sortingOrder = newSortingOrder; + $scope.filteredItems = _.sortBy($scope.data, $scope.sortingOrder); + $scope.filteredItems.reverse(); + } + $scope.groupToPages(); + // icon setup + + $('th i').each(function(){ + // icon reset + $(this).removeClass().addClass('icon-sort'); + }); + if (!$scope.reverse) + $('th.'+newSortingOrder+' i').removeClass().addClass('icon-chevron-up'); + else + $('th.'+newSortingOrder+' i').removeClass().addClass('icon-chevron-down'); + + }; + + }); + + } + }; + + $scope.set_refresh = function (state) { + $scope.refresh = state; + // if 'count' mode is selected, set decimal_points to zero automatically. + if ($scope.panel.mode === 'count') { + $scope.panel.decimal_points = 0; + } + }; + + $scope.close_edit = function() { + // Start refresh timer if enabled + if ($scope.panel.refresh.enable) { + $scope.set_timer($scope.panel.refresh.interval); + } + + if ($scope.refresh) { + // $scope.testMultivalued(); + $scope.get_data(); + } + $scope.refresh = false; + $scope.$emit('render'); + }; + + $scope.showMeta = function(term) { + if(_.isUndefined(term.meta)) { + return true; + } + if(term.meta === 'other' && !$scope.panel.other) { + return false; + } + if(term.meta === 'missing' && !$scope.panel.missing) { + return false; + } + return true; + }; + + + }); +}); diff --git a/src/app/panels/adLineChart/editor.html b/src/app/panels/adLineChart/editor.html new file mode 100644 index 000000000..24a8e933c --- /dev/null +++ b/src/app/panels/adLineChart/editor.html @@ -0,0 +1,6 @@ +
+
+ + +
+
diff --git a/src/app/panels/adLineChart/module.html b/src/app/panels/adLineChart/module.html new file mode 100644 index 000000000..f0e78ad3f --- /dev/null +++ b/src/app/panels/adLineChart/module.html @@ -0,0 +1,13 @@ +
+
+ + +
+
+
diff --git a/src/app/panels/adLineChart/module.js b/src/app/panels/adLineChart/module.js new file mode 100644 index 000000000..ab5dcfc40 --- /dev/null +++ b/src/app/panels/adLineChart/module.js @@ -0,0 +1,449 @@ +/* + ## Terms + + ### Parameters + * style :: A hash of css styles + * size :: top N + * arrangement :: How should I arrange the query results? 'horizontal' or 'vertical' + * chart :: Show a chart? 'none', 'bar', 'pie' + * donut :: Only applies to 'pie' charts. Punches a hole in the chart for some reason + * tilt :: Only 'pie' charts. Janky 3D effect. Looks terrible 90% of the time. + * lables :: Only 'pie' charts. Labels on the pie? + */ +define([ + 'angular', + 'app', + 'underscore', + 'jquery', + 'kbn' + ], + function (angular, app, _, $, kbn) { + 'use strict'; + var DEBUG = true; + console.log('adLineChart DEBUG : ' + DEBUG); + + var module = angular.module('kibana.panels.adLineChart', []); + app.useModule(module); + + module.controller('adLineChart', function($scope, $timeout, $filter, timer, querySrv, dashboard, filterSrv) { + $scope.panelMeta = { + exportfile: true, + editorTabs : [ + {title:'Queries', src:'app/partials/querySelect.html'} + ], + status : "Stable", + description : "Displays the results of a Solr facet as a pie chart, bar chart, or a table. Newly added functionality displays min/max/mean/sum of a stats field, faceted by the Solr facet field, again as a pie chart, bar chart or a table." + }; + + // Set and populate defaults + var _d = { + queries : { + mode : 'all', + ids : [], + query : '*:*', + custom : '' + }, + mode : 'count', // mode to tell which number will be used to plot the chart. + field : '', + stats_field : '', + decimal_points : 0, // The number of digits after the decimal point + exclude : [], + missing : false, + other : false, + size : 10000, + display:'block', + icon:"icon-caret-down", + sortBy : 'count', + threshold_first:3000, + threshold_second:5000, + order : 'descending', + style : { "font-size": '10pt'}, + fontsize:20, + linkage_id:'a', + donut : false, + tilt : false, + labels : true, + logAxis : false, + arrangement : 'horizontal', + chart : 'bar', + counter_pos : 'above', + exportSize : 10000, + lastColor : '', + spyable : true, + show_queries:true, + error : '', + max_rows : 1000, + chartColors : querySrv.colors, + refresh: { + enable: false, + interval: 2 + } + }; + _.defaults($scope.panel,_d); + + $scope.init = function () { + $scope.hits = 0; + //$scope.testMultivalued(); + + // Start refresh timer if enabled + if ($scope.panel.refresh.enable) { + $scope.set_timer($scope.panel.refresh.interval); + } + + $scope.$on('refresh',function(){ + $scope.get_data(); + }); + + $scope.get_data(); + }; + + $scope.get_time_range = function () { + var range = filterSrv.timeRange('min'); + return range; + }; + + $scope.testMultivalued = function() { + if($scope.panel.field && $scope.fields.typeList[$scope.panel.field] && $scope.fields.typeList[$scope.panel.field].schema.indexOf("M") > -1) { + $scope.panel.error = "Can't proceed with Multivalued field"; + return; + } + + if($scope.panel.stats_field && $scope.fields.typeList[$scope.panel.stats_field].schema.indexOf("M") > -1) { + $scope.panel.error = "Can't proceed with Multivalued field"; + return; + } + }; + $scope.display=function() { + if($scope.panel.display==='none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; + $scope.build_search = function(term) { + _.defaults(dashboard.current,{main_bn_node_name:''}); + _.defaults(dashboard.current,{line_chart_fq:''}); + dashboard.current.main_bn_node_name = term.term; + if (dashboard.current.fq) { + dashboard.current.line_chart_fq = dashboard.current.fq + '&fq=' + panel.metric_field + ':' + term.term; + } else { + dashboard.current.line_chart_fq = 'fq=' + panel.metric_field + ':' + term.term; + } + dashboard.refresh(); + }; + /** + * + * + * @param {String} filetype -'json', 'xml', 'csv' + */ + $scope.build_query = function(filetype, ex_fq) { + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + } + fq = fq + '&' + ex_fq; + var wt_json = '&wt=' + filetype; + var rows_limit = '&rows=' + $scope.panel.max_rows; // for terms, we do not need the actual response doc, so set rows=0 + var facet = ''; + var sort = '&sort=start_timestamp_l%20asc' + return querySrv.getORquery() + wt_json + rows_limit + fq + sort + facet + ($scope.panel.queries.custom !== null ? $scope.panel.queries.custom : ''); + }; + + $scope.exportfile = function(filetype) { + + var query = this.build_query(filetype, true); + + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + var request = $scope.sjs.Request().indices(dashboard.indices), + response; + + request.setQuery(query); + + response = request.doSearch(); + + // Populate scope when we have results + response.then(function(response) { + kbn.download_response(response, filetype, "terms"); + }); + }; + + $scope.set_timer = function(refresh_interval) { + $scope.panel.refresh.interval = refresh_interval; + if (_.isNumber($scope.panel.refresh.interval)) { + timer.cancel($scope.refresh_timer); + $scope.realtime(); + } else { + timer.cancel($scope.refresh_timer); + } + }; + + $scope.realtime = function() { + if ($scope.panel.refresh.enable) { + timer.cancel($scope.refresh_timer); + + $scope.refresh_timer = timer.register($timeout(function() { + $scope.realtime(); + $scope.get_data(); + }, $scope.panel.refresh.interval*1000)); + } else { + timer.cancel($scope.refresh_timer); + } + }; + + $scope.get_data = function() { + $scope.panel.mode = 'all'; + if(($scope.panel.linkage_id===dashboard.current.linkage_id)||dashboard.current.enable_linkage){ + // Make sure we have everything for the request to complete + if (dashboard.indices.length === 0) { + return; + } + + delete $scope.panel.error; + $scope.panelMeta.loading = true; + var request, results; + + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + request = $scope.sjs.Request().indices(dashboard.indices); + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + + // Populate the inspector panel + $scope.inspector = angular.toJson(JSON.parse(request.toString()), true); + + if (dashboard.current.line_chart_fq === undefined) {return ;} + if (dashboard.current.line_chart_anomaly_fq === undefined) {return ;} + var total_query = this.build_query('json', dashboard.current.line_chart_fq); + var anomaly_query = this.build_query('json', dashboard.current.line_chart_anomaly_fq); + + if (DEBUG) {console.log(total_query);} + if (DEBUG) {console.log(anomaly_query);} + // Set the panel's query + $scope.panel.queries.query = total_query + '\n' + anomaly_query; + + request.setQuery(total_query); + results = request.doSearch(); + // Populate scope when we have results + results.then(function (results) { + // Check for error and abort if found + if (!(_.isUndefined(results.error))) { + $scope.panel.error = $scope.parse_error(results.error.msg); + $scope.data = []; + $scope.panelMeta.loading = false; + $scope.$emit('render'); + return; + } + + $scope.panelMeta.loading = false; + $scope.data = []; + { + // In stats mode, set y-axis min to null so jquery.flot will set the scale automatically. + $scope.yaxis_min = null; + if (DEBUG) { console.log(results); } + _.each(results.response.docs, function (doc) { + //var slice = {label: facet_field, data: [[k, stats_obj['mean'], stats_obj['count'], stats_obj['max'], stats_obj['min'], stats_obj['stddev'], facet_field]], actions: true}; + var slice = {value: doc.value_f, timestamp: doc.start_timestamp_l, l: doc.down_margin_f, u:doc.up_margin_f}; + $scope.data.push(slice); + }); + } + }); + $scope.$emit('render'); + } + }; + + $scope.set_refresh = function (state) { + $scope.refresh = state; + // if 'count' mode is selected, set decimal_points to zero automatically. + if ($scope.panel.mode === 'count') { + $scope.panel.decimal_points = 0; + } + }; + + $scope.close_edit = function() { + // Start refresh timer if enabled + if ($scope.panel.refresh.enable) { + $scope.set_timer($scope.panel.refresh.interval); + } + + if ($scope.refresh) { + // $scope.testMultivalued(); + $scope.get_data(); + } + $scope.refresh = false; + $scope.$emit('render'); + }; + + $scope.showMeta = function(term) { + if(_.isUndefined(term.meta)) { + return true; + } + if(term.meta === 'other' && !$scope.panel.other) { + return false; + } + if(term.meta === 'missing' && !$scope.panel.missing) { + return false; + } + return true; + }; + + + }); + + module.directive('lineChart', function(querySrv,dashboard,filterSrv) { + return { + restrict: 'A', + link: function(scope, elem) { + var myChart; + // Receive render events + scope.$on('render',function(){ + render_panel(); + }); + + // Re-render if the window is resized + angular.element(window).bind('resize', function(){ + render_panel(); + }); + + // Function for rendering panel + function render_panel() { + var plot, chartData; + var colors = []; + + // IE doesn't work without this + elem.css({height: scope.panel.height || scope.row.height}); + + // Make a clone we can operate on. + + chartData = _.clone(scope.data); + chartData = scope.panel.missing ? chartData : + _.without(chartData, _.findWhere(chartData, {meta: 'missing'})); + chartData = scope.panel.other ? chartData : + _.without(chartData, _.findWhere(chartData, {meta: 'other'})); + var line_id = scope.$id; + require(['echarts'], function (ec) { + var echarts = ec; + if(myChart){ + myChart.dispose(); + } + myChart = echarts.init(document.getElementById(line_id)); + myChart.showLoading(); + if (chartData === []) return ; + myChart.hideLoading(); + var base = -chartData.reduce(function (min, val) { + return Math.floor(Math.min(min, val.l)); + }, Infinity); + var option = { + title: { + text: dashboard.current.line_chart_name, + left: 'center' + }, + tooltip: { + trigger: 'axis', + formatter: function (params) { + return params[2].name + '
' + params[2].value; + } + }, + grid: { + left: '3%', + right: '4%', + bottom: '3%', + containLabel: false + }, + xAxis: { + type: 'category', + data: chartData.map(function (item) { + var date = echarts.format.formatTime('yyyy/MM/dd hh:mm:ss', item.timestamp); + return date; + }), + splitLine: { + show: false + }, + boundaryGap: false, + axisLine:{ + lineStyle:{ + color:'#aaaaaa', + width:1 + } + } + }, + yAxis: { + axisLabel: { + formatter: function (val) { + return (val - base); + } + }, + axisPointer: { + label: { + formatter: function (params) { + console.log(params); + return (params.value - base).toFixed(1); + } + } + }, + splitNumber: 3, + splitLine: { + show: false + }, + axisLine:{ + lineStyle:{ + color:'#aaaaaa', + width:1 + } + } + }, + series: [{ + name: 'L', + type: 'line', + data: chartData.map(function (item) { + return item.l + base; + }), + lineStyle: { + normal: { + opacity: 0 + } + }, + stack: 'confidence-band', + symbol: 'none' + }, { + name: 'U', + type: 'line', + data: chartData.map(function (item) { + return item.u - item.l; + }), + lineStyle: { + normal: { + opacity: 0 + } + }, + areaStyle: { + normal: { + color: '#ccc' + } + }, + stack: 'confidence-band', + symbol: 'none' + }, { + type: 'line', + data: chartData.map(function (item) { + return item.value + base; + }), + hoverAnimation: false, + symbolSize: 6, + itemStyle: { + normal: { + color: '#c23531' + } + }, + showSymbol: false + }] + }; + myChart.setOption(option); + }); + } + } + }; + }); +}); diff --git a/src/app/panels/adMetrics/editor.html b/src/app/panels/adMetrics/editor.html new file mode 100644 index 000000000..29e4198df --- /dev/null +++ b/src/app/panels/adMetrics/editor.html @@ -0,0 +1,49 @@ +
+
+
+
Add Column
+ + +
+
+
+
Columns Click to remove
+ {{field}} +
+
+
+
+ + +
+
+ + +
+
+ +
+ + +
Model Settings
+
+ + +
+
+ + +
+
+ + +
+
+ +
Tooltip Settings
+
+
+ + +
+
diff --git a/src/app/panels/adMetrics/interval.js b/src/app/panels/adMetrics/interval.js new file mode 100644 index 000000000..673371fcf --- /dev/null +++ b/src/app/panels/adMetrics/interval.js @@ -0,0 +1,57 @@ +define([ + 'kbn' +], +function (kbn) { + 'use strict'; + + /** + * manages the interval logic + * @param {[type]} interval_string An interval string in the format '1m', '1y', etc + */ + function Interval(interval_string) { + this.string = interval_string; + + var info = kbn.describe_interval(interval_string); + this.type = info.type; + this.ms = info.sec * 1000 * info.count; + + // does the length of the interval change based on the current time? + if (this.type === 'y' || this.type === 'M') { + // we will just modify this time object rather that create a new one constantly + this.get = this.get_complex; + this.date = new Date(0); + } else { + this.get = this.get_simple; + } + } + + Interval.prototype = { + toString: function () { + return this.string; + }, + after: function(current_ms) { + return this.get(current_ms, 1); + }, + before: function (current_ms) { + return this.get(current_ms, -1); + }, + get_complex: function (current, delta) { + this.date.setTime(current); + switch(this.type) { + case 'M': + this.date.setUTCMonth(this.date.getUTCMonth() + delta); + break; + case 'y': + this.date.setUTCFullYear(this.date.getUTCFullYear() + delta); + break; + } + return this.date.getTime(); + }, + get_simple: function (current, delta) { + return current + (delta * this.ms); + } + }; + + return Interval; + +}); \ No newline at end of file diff --git a/src/app/panels/adMetrics/module.html b/src/app/panels/adMetrics/module.html new file mode 100644 index 000000000..47160032e --- /dev/null +++ b/src/app/panels/adMetrics/module.html @@ -0,0 +1,48 @@ +
+ + + + + + + +
+
diff --git a/src/app/panels/adMetrics/module.js b/src/app/panels/adMetrics/module.js new file mode 100644 index 000000000..aa4a6fa18 --- /dev/null +++ b/src/app/panels/adMetrics/module.js @@ -0,0 +1,558 @@ +/* + + ## Anomaly Detection Metrics + + ### Parameters + * auto_int :: Auto calculate data point interval? + * resolution :: If auto_int is enables, shoot for this many data points, rounding to + sane intervals + * interval :: Datapoint interval in elasticsearch date math format (eg 1d, 1w, 1y, 5y) + * fill :: Only applies to line charts. Level of area shading from 0-10 + * linewidth :: Only applies to line charts. How thick the line should be in pixels + While the editor only exposes 0-10, this can be any numeric value. + Set to 0 and you'll get something like a scatter plot + * timezone :: This isn't totally functional yet. Currently only supports browser and utc. + browser will adjust the x-axis labels to match the timezone of the user's + browser + * spyable :: Dislay the 'eye' icon that show the last elasticsearch query + * zoomlinks :: Show the zoom links? + * bars :: Show bars in the chart + * stack :: Stack multiple queries. This generally a crappy way to represent things. + You probably should just use a line chart without stacking + * points :: Should circles at the data points on the chart + * lines :: Line chart? Sweet. + * legend :: Show the legend? + * x-axis :: Show x-axis labels and grid lines + * y-axis :: Show y-axis labels and grid lines + * interactive :: Allow drag to select time range + +*/ +define([ + 'angular', + 'app', + 'jquery', + 'underscore', + 'kbn', + 'moment', + './timeSeries' +], +function (angular, app, $, _, kbn, moment, timeSeries) { + 'use strict'; + var module = angular.module('kibana.panels.adMetrics', []); + app.useModule(module); + + var DEBUG = false; + console.log('adMetrics DEBUG : ' + DEBUG); + module.controller('adMetrics', function($scope, $q, $http, $routeParams, querySrv, dashboard, filterSrv) { + $scope.panelMeta = { + modals : [ + { + description: "Inspect", + icon: "icon-info-sign", + partial: "app/partials/inspector.html", + show: $scope.panel.spyable + } + ], + editorTabs : [ + { + title:'Queries', + src:'app/partials/querySelect.html' + } + ], + status : "Stable", + description : "A bucketed time series chart of the current query, including all applied time and non-time filters, when used in count mode. Uses Solr’s facet.range query parameters. In values mode, it plots the value of a specific field over time, and allows the user to group field values by a second field." + }; + + // Set and populate defaults + var _d; + _d = { + mode: 'value', + queries: { + mode: 'all', + ids: [], + query: '*:*', + custom: '' + }, + max_rows: 1000, // maximum number of rows returned from Solr (also use this for group.limit to simplify UI setting) + cut_number: 100, + anomaly_th: 0.70, + reverse: 0, + group_field: null, + auto_int: true, + total_first: '%', + fontsize: 20, + field_color: '#209bf8', + resolution: 100, + value_sort: 'rs_timestamp', + interval: '5m', + intervals: ['auto', '1s', '1m', '5m', '10m', '30m', '1h', '3h', '12h', '1d', '1w', '1M', '1y'], + fill: 0, + linewidth: 3, + chart: 'stacking', + chartColors: ['#209bf8', '#f4d352', '#ccf452', '#8cf452', '#3cee2b', '#f467d8', '#2fd7ee'], + timezone: 'browser', // browser, utc or a standard timezone + spyable: true, + zoomlinks: true, + bars: true, + stack: true, + label: true, + points: false, + lines: false, + lines_smooth: false, // Enable 'smooth line' mode by removing zero values from the plot. + legend: true, + 'x-axis': true, + 'y-axis': true, + percentage: false, + interactive: true, + options: true, + show_queries: true, + tooltip: { + value_type: 'cumulative', + query_as_alias: false + }, + jobid: '', + job_status: 'Ready', + metric_field: 'facet_name_s', + ad_name: 'ad_name', + fields:[] + }; + + _.defaults($scope.panel,_d); + + $scope.init = function() { + // Hide view options by default + if (DEBUG) { console.log('init'); } + $scope.options = false; + $scope.$on('refresh',function(){ + $scope.get_data(); + }); + + $scope.get_data(); + + }; + + $scope.set_interval = function(interval) { + if(interval !== 'auto') { + $scope.panel.auto_int = false; + $scope.panel.interval = interval; + } else { + $scope.panel.auto_int = true; + } + }; + + $scope.interval_label = function(interval) { + return $scope.panel.auto_int && interval === $scope.panel.interval ? interval+" (auto)" : interval; + }; + + $scope.set_refresh = function (state) { + $scope.refresh = state; + // if 'count' mode is selected, set decimal_points to zero automatically. + if ($scope.panel.mode === 'count') { + $scope.panel.decimal_points = 0; + } + $scope.get_data(); + }; + /** + * The time range effecting the panel + * @return {[type]} [description] + */ + $scope.get_time_range = function () { + var range = $scope.range = filterSrv.timeRange('min'); + return range; + }; + + $scope.get_interval = function () { + var interval = $scope.panel.interval, + range; + if ($scope.panel.auto_int) { + range = $scope.get_time_range(); + if (range) { + interval = kbn.secondsToHms( + kbn.calculate_interval(range.from, range.to, $scope.panel.resolution, 0) / 1000 + ); + } + } + $scope.panel.interval = interval || '10m'; + return $scope.panel.interval; + }; + + $scope.toggle_field = function(field) { + if (_.indexOf($scope.panel.fields, field) > -1) { + $scope.panel.fields = _.without($scope.panel.fields, field); + } else { + $scope.panel.fields.push(field); + } + $scope.$emit('render'); + }; + + /** + * Fetch the data for a chunk of a queries results. Multiple segments occur when several indicies + * need to be consulted (like timestamped logstash indicies) + * + * The results of this function are stored on the scope's data property. This property will be an + * array of objects with the properties info, time_series, and hits. These objects are used in the + * render_panel function to create the historgram. + * + * !!! Solr does not need to fetch the data in chunk because it uses a facet search and retrieve + * !!! all events from a single query. + * + * @param {number} segment The segment count, (0 based) + * @param {number} query_id The id of the query, generated on the first run and passed back when + * this call is made recursively for more segments + */ + $scope.get_data = function(segment) { + if (DEBUG) { console.log('get data start.'); } + if (_.isUndefined(segment)) { + segment = 0; + } + delete $scope.panel.error; + + // Make sure we have everything for the request to complete + if(dashboard.indices.length === 0) { + return; + } + var _range = $scope.get_time_range(); + var _interval = $scope.get_interval(_range); + + if ($scope.panel.auto_int) { + $scope.panel.interval = kbn.secondsToHms( + kbn.calculate_interval(_range.from,_range.to,$scope.panel.resolution,0)/1000); + } + + $scope.panelMeta.loading = true; + + // Solr + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + var request = $scope.sjs.Request().indices(dashboard.indices[segment]); + // $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + + if(_.isNull($scope.panel.value_field)) { + $scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified"; + return; + } + + + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + } + + + var start_time = filterSrv.getStartTime(); + var end_time = filterSrv.getEndTime(); + + $scope.panel.start_time = start_time; + $scope.panel.end_time = end_time; + + // facet.range.end does NOT accept * as a value, need to convert it to NOW + if (end_time === '*') { + end_time = 'NOW'; + } + + + var wt_json = '&wt=json'; + var anomaly_th = $scope.panel.anomaly_th; + var sort_field = '&sort='+'start_timestamp_l'+'%20asc'; + var rows_limit = '&rows='+$scope.panel.max_rows; + var facet = ''; + var fl = ''; + fq = fq + '&fq=anomaly_f:[' + anomaly_th + '%20TO%20*]'; + fq = fq + '&fq=result_s:ad'; + var mypromises = []; + var arr_id = []; + var index = 0; + if (!_.isUndefined($routeParams.adValue)) { + $scope.panel.ad_name = $routeParams.adValue; + } + + _.defaults(dashboard.current,{anomaly_name:''}); + dashboard.current.anomaly_name = $scope.panel.ad_name; + var temp_fq = fq + '&fq=ad_name_s:'+$scope.panel.ad_name; + var temp_q = 'q=*:*' + wt_json + rows_limit + temp_fq + facet + fl + sort_field; + $scope.panel.queries.query += temp_q + "\n"; + if ($scope.panel.queries.custom !== null) { + request = request.setQuery(temp_q + $scope.panel.queries.custom); + } else { + request = request.setQuery(temp_q); + } + mypromises.push(request.doSearch()); + arr_id.push(0); + + $scope.data = []; + if (dashboard.current.services.query.ids.length >= 1) { + $q.all(mypromises).then(function(results) { + $scope.panelMeta.loading = false; + // Convert facet ids to numbers + // var facetIds = _.map(_.keys(results.facets),function(k){return parseInt(k, 10);}); + //var facetIds = [0]; // Need to fix this + + // Make sure we're still on the same query/queries + // TODO: We probably DON'T NEED THIS unless we have to support multiple queries in query module. + // if ($scope.query_id === query_id && _.difference(facetIds, $scope.panel.queries.ids).length === 0) { + var i = 0, + time_series, + hits; + + _.each(arr_id, function(id,index) { + // Check for error and abort if found + if (!(_.isUndefined(results[index].error))) { + $scope.panel.error = $scope.parse_error(results[index].error.msg); + return; + } + // we need to initialize the data variable on the first run, + // and when we are working on the first segment of the data. + if (_.isUndefined($scope.data[i]) || segment === 0) { + time_series = new timeSeries.ZeroFilled({ + interval: _interval, + start_date: _range && _range.from, + end_date: _range && _range.to, + fill_style: 'minimal' + }); + hits = 0; + } else { + time_series = $scope.data[i].time_series; + hits = 0; + $scope.hits = 0; + } + $scope.data[i] = results[index].response.docs; + i++; + }); + + // Tell the histogram directive to render. + $scope.$emit('render'); + }); + } + }; + }); + + module.directive('metricsChart', function(querySrv,dashboard,filterSrv) { + return { + restrict: 'A', + link: function(scope, elem) { + var myChart; + // Receive render events + scope.$on('render',function(){ + render_panel(); + }); + + // Re-render if the window is resized + angular.element(window).bind('resize', function(){ + render_panel(); + }); + + // Function for rendering panel + function render_panel() { + var plot, chartData; + var colors = []; + + // IE doesn't work without this + elem.css({height:scope.panel.height||scope.row.height}); + + // Make a clone we can operate on. + + chartData = _.clone(scope.data); + chartData = scope.panel.missing ? chartData : + _.without(chartData,_.findWhere(chartData,{meta:'missing'})); + chartData = scope.panel.other ? chartData : + _.without(chartData,_.findWhere(chartData,{meta:'other'})); + + var metrics_id = scope.$id; + require(['echarts'], function(ec){ + var echarts = ec; + if(myChart){ + myChart.dispose(); + } + var labelcolor = false; + if (dashboard.current.style === 'dark'){ + labelcolor = true; + } + var cut_number = scope.panel.cut_number + 1; + myChart = echarts.init(document.getElementById(metrics_id)); + var start_time = Date.parse(new Date(scope.get_time_range()['from'])); + var end_time = Date.parse(new Date(scope.get_time_range()['to'])); + var step = (end_time-start_time)/cut_number+1; + var ad_name = scope.panel.ad_name; + var metric_field = scope.panel.metric_field; + var fields = scope.panel.fields; + var dates = []; + var timestamps = []; + if (DEBUG) {console.log(scope.get_time_range());} + if (DEBUG) {console.log(start_time);} + + var data = []; var index = 0; var metric2index = {}; var index2metric = {}; var metric_names = []; + for (var timestamp = start_time; timestamp <= end_time; timestamp += step) { + timestamps.push(timestamp); + dates.push( + echarts.format.formatTime('yyyy/MM/dd hh:mm:ss', timestamp) + ); + data.push({}); + } + if (DEBUG) { console.log(ad_name); } + if (DEBUG) {console.log(chartData); } + if (DEBUG) {console.log(fields); } + chartData.map(function (anomalys) { + anomalys.map(function (anomaly) { + var date_index = Math.floor((anomaly['start_timestamp_l'] - start_time) / step); + if (date_index >= 0) { + if (date_index < dates.length) { + var metric_field = scope.panel.metric_field; + var metric_value = anomaly.value_f; + var anomaly_value = anomaly.anomaly_f; + var from_timestamp = timestamps[date_index]; + var to_timestamp = timestamps[date_index] + step; + var solr_reader_url = anomaly.solr_reader_url_s; + var solr_writer_url = anomaly.solr_writer_url_s; + var stats_facet = anomaly.stats_facet_s; + var facet_name = anomaly.facet_name_s; + var metric = anomaly[metric_field]; + + if (fields.length > 0) { + var flag = -1; + for (var key in fields) { + var field = fields[key]; + if (field === metric) { flag = 1; } + } + if (flag === -1) {return;} + } + if (data[date_index][metric] === undefined) { + data[date_index][metric] = []; + } + if (metric2index[metric] === undefined) { + metric2index[metric] = index; + index2metric[index] = metric; + metric_names.push(metric); + index += 1; + } + data[date_index][metric].push({ + date_index: date_index, + anomaly_date: dates[date_index], + anomaly_value: anomaly_value, + metric_value: metric_value, + from_timestamp: from_timestamp, + to_timestamp: to_timestamp, + solr_reader_url: solr_reader_url, + solr_writer_url: solr_writer_url, + stats_facet: stats_facet, + facet_name: facet_name + }); + } + } + }); + }); + var show_data = []; + var max_num = 0; + for (var date_index = 0; date_index < dates.length; date_index++) { + for (var metric in data[date_index]) { + if (data[date_index][metric].length > 0) { + show_data.push([date_index, metric2index[metric], data[date_index][metric].length]); + } + if (data[date_index][metric].length > max_num) { + max_num = data[date_index][metric].length; + } + } + } + if (DEBUG) { console.log(data); } + if (DEBUG) { console.log(max_num); } + if (DEBUG) { console.log(metric2index); } + var option = { + tooltip: { + show: false + }, + animation: false, + grid: { + height: '90%', + y: '5%', + x: '10%' + }, + xAxis: { + type: 'category', + data: dates, + splitArea: { + show: true + }, + axisLine:{ + lineStyle:{ + color:'#aaaaaa', + width:1 + } + } + }, + yAxis: { + type: 'category', + data: metric_names, + splitArea: { + show: true + }, + axisLine:{ + lineStyle:{ + color:'#aaaaaa', + width:1 + } + } + }, + visualMap: { + min: 0, + max: max_num, + show: false + }, + series: [{ + name: 'anomaly', + type: 'heatmap', + data: show_data, + label: { + normal: { + show: true + } + } + }] + }; + + myChart.setOption(option); + + myChart.on('click', function (params) { + if (DEBUG) { console.log(params); } + if (DEBUG) { console.log(data); } + var anomaly_th = scope.panel.anomaly_th; + var x = params.data[0]; + var y = index2metric[params.data[1]]; + if (data[x][y][0] === undefined){ + return ; + } + var from_timestamp = data[x][y][0].from_timestamp; + var to_timestamp = data[x][y][0].to_timestamp; + var facet_name = data[x][y][0].facet_name; + if (DEBUG) { console.log(from_timestamp + " " + to_timestamp + ' ' + facet_name);} + var fq = 'fq=start_timestamp_l:[' + Math.floor(from_timestamp) + '%20TO%20' + Math.floor(to_timestamp)+']'; + fq = fq + '&fq=ad_name_s:' + ad_name + '&fq='+metric_field+':'+facet_name; + var anomaly_fq = fq + '&fq=anomaly_f:[' + anomaly_th + '%20TO%20*]'; + if (DEBUG) { console.log(fq); } + _.defaults(dashboard.current,{anomaly_fq:''}); + _.defaults(dashboard.current,{anomaly_name:''}); + _.defaults(dashboard.current,{anomaly_solr_reader_url:''}); + _.defaults(dashboard.current,{anomaly_stats_facet:''}); + _.defaults(dashboard.current,{anomaly_facet_name:''}); + _.defaults(dashboard.current,{fq:''}); + dashboard.current.anomaly_fq = anomaly_fq; + dashboard.current.fq = fq; + dashboard.current.anomaly_name = ad_name; + dashboard.current.anomaly_solr_reader_url = data[x][y][0].anomaly_solr_reader_url; + dashboard.current.anomaly_stats_facet = data[x][y][0].anomaly_stats_facet; + dashboard.current.anomaly_facet_name = data[x][y][0].anomaly_facet_name; + /* filterSrv.set({ + type : 'time', + from : moment.utc(Number(from_timestamp)).toDate(), + to : moment.utc(Number(to_timestamp)).toDate(), + field : filterSrv.getTimeField() + }); */ + dashboard.refresh(); + }); + }); + } + } + }; + }); + + +}); diff --git a/src/app/panels/adMetrics/timeSeries.js b/src/app/panels/adMetrics/timeSeries.js new file mode 100644 index 000000000..722768e22 --- /dev/null +++ b/src/app/panels/adMetrics/timeSeries.js @@ -0,0 +1,178 @@ +define([ + 'underscore', + './interval' +], +function (_, Interval) { + 'use strict'; + + var ts = {}; + + // map compatable parseInt + function base10Int(val) { + return parseInt(val, 10); + } + + // trim the ms off of a time, but return it with empty ms. + function getDatesTime(date) { + return Math.floor(date.getTime() / 1000)*1000; + } + /** + * Certain graphs require 0 entries to be specified for them to render + * properly (like the line graph). So with this we will caluclate all of + * the expected time measurements, and fill the missing ones in with 0 + * @param {object} opts An object specifying some/all of the options + * + * OPTIONS: + * @opt {string} interval The interval notion describing the expected spacing between + * each data point. + * @opt {date} start_date (optional) The start point for the time series, setting this and the + * end_date will ensure that the series streches to resemble the entire + * expected result + * @opt {date} end_date (optional) The end point for the time series, see start_date + * @opt {string} fill_style Either "minimal", or "all" describing the strategy used to zero-fill + * the series. + */ + ts.ZeroFilled = function (opts) { + opts = _.defaults(opts, { + interval: '10m', + start_date: null, + end_date: null, + fill_style: 'minimal' + }); + + // the expected differenece between readings. + this.interval = new Interval(opts.interval); + + // will keep all values here, keyed by their time + this._data = {}; + this.start_time = opts.start_date && getDatesTime(opts.start_date); + this.end_time = opts.end_date && getDatesTime(opts.end_date); + this.opts = opts; + }; + + /** + * Add a row + * @param {int} time The time for the value, in + * @param {any} value The value at this time + */ + ts.ZeroFilled.prototype.addValue = function (time, value) { + if (time instanceof Date) { + time = getDatesTime(time); + } else { + time = base10Int(time); + } + if (!isNaN(time)) { + this._data[time] = (_.isUndefined(value) ? 0 : value); + } + this._cached_times = null; + }; + + /** + * Get an array of the times that have been explicitly set in the series + * @param {array} include (optional) list of timestamps to include in the response + * @return {array} An array of integer times. + */ + ts.ZeroFilled.prototype.getOrderedTimes = function (include) { + var times = _.map(_.keys(this._data), base10Int); + if (_.isArray(include)) { + times = times.concat(include); + } + return _.uniq(times.sort(function (a, b) { + // decending numeric sort + return a - b; + }), true); + }; + + /** + * return the rows in the format: + * [ [time, value], [time, value], ... ] + * + * Heavy lifting is done by _get(Min|All)FlotPairs() + * @param {array} required_times An array of timestamps that must be in the resulting pairs + * @return {array} + */ + ts.ZeroFilled.prototype.getFlotPairs = function (required_times) { + var times = this.getOrderedTimes(required_times), + strategy, + pairs; + + if(this.opts.fill_style === 'all') { + strategy = this._getAllFlotPairs; + } else { + strategy = this._getMinFlotPairs; + } + + pairs = _.reduce( + times, // what + strategy, // how + [], // where + this // context + ); + + // if the first or last pair is inside either the start or end time, + // add those times to the series with null values so the graph will stretch to contain them. + if (this.start_time && (pairs.length === 0 || pairs[0][0] > this.start_time)) { + pairs.unshift([this.start_time, null]); + } + if (this.end_time && (pairs.length === 0 || pairs[pairs.length - 1][0] < this.end_time)) { + pairs.push([this.end_time, null]); + } + + return pairs; + }; + + /** + * ** called as a reduce stragegy in getFlotPairs() ** + * Fill zero's on either side of the current time, unless there is already a measurement there or + * we are looking at an edge. + * @return {array} An array of points to plot with flot + */ + ts.ZeroFilled.prototype._getMinFlotPairs = function (result, time, i, times) { + var next, expected_next, prev, expected_prev; + + // check for previous measurement + if (i > 0) { + prev = times[i - 1]; + expected_prev = this.interval.before(time); + if (prev < expected_prev) { + result.push([expected_prev, 0]); + } + } + + // add the current time + result.push([ time, this._data[time] || 0 ]); + + // check for next measurement + if (times.length > i) { + next = times[i + 1]; + expected_next = this.interval.after(time); + if (next > expected_next) { + result.push([expected_next, 0]); + } + } + + return result; + }; + + /** + * ** called as a reduce stragegy in getFlotPairs() ** + * Fill zero's to the right of each time, until the next measurement is reached or we are at the + * last measurement + * @return {array} An array of points to plot with flot + */ + ts.ZeroFilled.prototype._getAllFlotPairs = function (result, time, i, times) { + var next, expected_next; + + result.push([ times[i], this._data[times[i]] || 0 ]); + next = times[i + 1]; + expected_next = this.interval.after(time); + for(; times.length > i && next > expected_next; expected_next = this.interval.after(expected_next)) { + result.push([expected_next, 0]); + } + + return result; + }; + + + return ts; +}); \ No newline at end of file diff --git a/src/app/panels/adStatistics/editor.html b/src/app/panels/adStatistics/editor.html new file mode 100644 index 000000000..1c4016c98 --- /dev/null +++ b/src/app/panels/adStatistics/editor.html @@ -0,0 +1,10 @@ +
+
+ + +
+
+ + +
+
\ No newline at end of file diff --git a/src/app/panels/adStatistics/module.html b/src/app/panels/adStatistics/module.html new file mode 100644 index 000000000..a29b5954e --- /dev/null +++ b/src/app/panels/adStatistics/module.html @@ -0,0 +1,62 @@ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +
指标/事务å å¼‚常数釠
+ +
{{term.term}}{{term.count}} + +
+ + + +
+ +
diff --git a/src/app/panels/adStatistics/module.js b/src/app/panels/adStatistics/module.js new file mode 100644 index 000000000..c4d476ace --- /dev/null +++ b/src/app/panels/adStatistics/module.js @@ -0,0 +1,461 @@ +/* + ## Anomaly Detection Statistics + + ### Parameters + * style :: A hash of css styles + * size :: top N + * arrangement :: How should I arrange the query results? 'horizontal' or 'vertical' + * chart :: Show a chart? 'none', 'bar', 'pie' + * donut :: Only applies to 'pie' charts. Punches a hole in the chart for some reason + * tilt :: Only 'pie' charts. Janky 3D effect. Looks terrible 90% of the time. + * lables :: Only 'pie' charts. Labels on the pie? + */ +define([ + 'angular', + 'app', + 'underscore', + 'jquery', + 'kbn' + ], + function (angular, app, _, $, kbn) { + 'use strict'; + var DEBUG = false; + console.log('adStatistics DEBUG : ' + DEBUG); + + var module = angular.module('kibana.panels.adStatistics', []); + app.useModule(module); + + module.controller('adStatistics', function($scope, $timeout, $filter, timer, querySrv, dashboard, filterSrv) { + $scope.panelMeta = { + exportfile: true, + editorTabs : [ + {title:'Queries', src:'app/partials/querySelect.html'} + ], + status : "Stable", + description : "Displays the results of a Solr facet as a pie chart, bar chart, or a table. Newly added functionality displays min/max/mean/sum of a stats field, faceted by the Solr facet field, again as a pie chart, bar chart or a table." + }; + + // Set and populate defaults + var _d = { + queries : { + mode : 'all', + ids : [], + query : '*:*', + custom : '' + }, + mode : 'count', // mode to tell which number will be used to plot the chart. + field : '', + stats_field : '', + decimal_points : 0, // The number of digits after the decimal point + exclude : [], + missing : false, + other : false, + size : 10000, + display:'block', + icon:"icon-caret-down", + sortBy : 'count', + threshold_first:3000, + threshold_second:5000, + order : 'descending', + style : { "font-size": '10pt'}, + fontsize:20, + linkage_id:'a', + donut : false, + tilt : false, + labels : true, + logAxis : false, + arrangement : 'horizontal', + chart : 'bar', + counter_pos : 'above', + exportSize : 10000, + lastColor : '', + spyable : true, + show_queries:true, + error : '', + chartColors : querySrv.colors, + refresh: { + enable: false, + interval: 2 + }, + }; + _.defaults($scope.panel,_d); + + $scope.init = function () { + $scope.hits = 0; + //$scope.testMultivalued(); + + // Start refresh timer if enabled + if ($scope.panel.refresh.enable) { + $scope.set_timer($scope.panel.refresh.interval); + } + + $scope.$on('refresh',function(){ + $scope.get_data(); + }); + + $scope.get_data(); + }; + + $scope.get_time_range = function () { + var range = filterSrv.timeRange('min'); + return range; + }; + + $scope.testMultivalued = function() { + if($scope.panel.field && $scope.fields.typeList[$scope.panel.field] && $scope.fields.typeList[$scope.panel.field].schema.indexOf("M") > -1) { + $scope.panel.error = "Can't proceed with Multivalued field"; + return; + } + + if($scope.panel.stats_field && $scope.fields.typeList[$scope.panel.stats_field].schema.indexOf("M") > -1) { + $scope.panel.error = "Can't proceed with Multivalued field"; + return; + } + }; + $scope.display=function() { + if($scope.panel.display==='none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + + }; + $scope.build_search = function(term) { + dashboard.current.main_bn_node_name = term.term; + if (dashboard.current.fq) { + dashboard.current.line_chart_fq = dashboard.current.fq + '&fq=' + $scope.panel.stats_field + ':' + term.term; + } else { + dashboard.current.line_chart_fq = 'fq=' + $scope.panel.stats_field + ':' + term.term; + } + if (dashboard.current.anomaly_fq) { + dashboard.current.line_chart_anomaly_fq = dashboard.current.anomaly_fq + '&fq=' + $scope.panel.stats_field + ':' + term.term; + } else { + dashboard.current.line_chart_anomaly_fq = 'fq=' + $scope.panel.stats_field + ':' + term.term; + } + dashboard.current.line_chart_name = term.term; + if (DEBUG) console.log(dashboard.current.line_chart_fq); + if (DEBUG) console.log(dashboard.current.line_chart_anomaly_fq); + dashboard.refresh(); + }; + /** + * + * + * @param {String} filetype -'json', 'xml', 'csv' + */ + $scope.build_query = function(filetype, isForExport) { + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + } + if (dashboard.current.anomaly_fq) { + fq = fq + '&' + dashboard.current.anomaly_fq; + } + var wt_json = '&wt=' + filetype; + var rows_limit = isForExport ? '&rows=0' : ''; // for terms, we do not need the actual response doc, so set rows=0 + var facet = ''; + { + // stats does not support something like facet.limit, so we have to sort and limit the results manually. + facet = '&stats=true&stats.facet='+$scope.panel.stats_field + '&stats.field=value_f' + '&facet.missing=true'; + } + + var exclude_length = $scope.panel.exclude.length; + var exclude_filter = ''; + if(exclude_length > 0){ + for (var i = 0; i < exclude_length; i++) { + if($scope.panel.exclude[i] !== "") { + exclude_filter += '&fq=-' + $scope.panel.field +":"+ $scope.panel.exclude[i]; + } + } + } + return querySrv.getORquery() + wt_json + rows_limit + fq + exclude_filter + facet + ($scope.panel.queries.custom !== null ? $scope.panel.queries.custom : ''); + }; + + $scope.exportfile = function(filetype) { + + var query = this.build_query(filetype, true); + + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + var request = $scope.sjs.Request().indices(dashboard.indices), + response; + + request.setQuery(query); + + response = request.doSearch(); + + // Populate scope when we have results + response.then(function(response) { + kbn.download_response(response, filetype, "terms"); + }); + }; + + $scope.set_timer = function(refresh_interval) { + $scope.panel.refresh.interval = refresh_interval; + if (_.isNumber($scope.panel.refresh.interval)) { + timer.cancel($scope.refresh_timer); + $scope.realtime(); + } else { + timer.cancel($scope.refresh_timer); + } + }; + + $scope.realtime = function() { + if ($scope.panel.refresh.enable) { + timer.cancel($scope.refresh_timer); + + $scope.refresh_timer = timer.register($timeout(function() { + $scope.realtime(); + $scope.get_data(); + }, $scope.panel.refresh.interval*1000)); + } else { + timer.cancel($scope.refresh_timer); + } + }; + + $scope.get_data = function() { + $scope.panel.mode = 'all'; + if(($scope.panel.linkage_id===dashboard.current.linkage_id)||dashboard.current.enable_linkage){ + // Make sure we have everything for the request to complete + if (dashboard.indices.length === 0) { + return; + } + + delete $scope.panel.error; + $scope.panelMeta.loading = true; + var request, results; + + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + request = $scope.sjs.Request().indices(dashboard.indices); + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + + // Populate the inspector panel + $scope.inspector = angular.toJson(JSON.parse(request.toString()), true); + + var query = this.build_query('json', false); + if (DEBUG) {console.log(query);} + // Set the panel's query + $scope.panel.queries.query = query; + + request.setQuery(query); + results = request.doSearch(); + // Populate scope when we have results + results.then(function (results) { + // Check for error and abort if found + if (!(_.isUndefined(results.error))) { + $scope.panel.error = $scope.parse_error(results.error.msg); + $scope.data = []; + $scope.panelMeta.loading = false; + $scope.$emit('render'); + return; + } + + // Function for validating HTML color by assign it to a dummy
+ // and let the browser do the work of validation. + var isValidHTMLColor = function (color) { + // clear attr first, before comparison + $('#colorTest').removeAttr('style'); + var valid = $('#colorTest').css('color'); + $('#colorTest').css('color', color); + + if (valid === $('#colorTest').css('color')) { + return false; + } else { + return true; + } + }; + + var sum = 0; + var k = 0; + $scope.panelMeta.loading = false; + $scope.hits = results.response.numFound; + $scope.data = []; + { + // In stats mode, set y-axis min to null so jquery.flot will set the scale automatically. + $scope.yaxis_min = null; + if (DEBUG) { console.log(results.stats); } + _.each(results.stats.stats_fields.value_f.facets[$scope.panel.stats_field], function (stats_obj, stats_field) { + k = k + 1; + //var slice = {label: facet_field, data: [[k, stats_obj['mean'], stats_obj['count'], stats_obj['max'], stats_obj['min'], stats_obj['stddev'], facet_field]], actions: true}; + var term = stats_field; + var slice = {term: term, index: k, name: dashboard.current.anomaly_name, count: stats_obj['count'], max: stats_obj['max'], min: stats_obj['min'], stddev: stats_obj['stddev'], actions: true}; + $scope.data.push(slice); + }); + } + + + // Slice it according to panel.size, and then set the x-axis values with k. + // $scope.data = $scope.data.slice(0, $scope.panel.size); + + if ($scope.panel.field && $scope.fields.typeList[$scope.panel.field] && $scope.fields.typeList[$scope.panel.field].schema.indexOf("T") > -1) { + $scope.hits = sum; + } + /* + $scope.data.push({ + label: 'Missing field', + // data:[[k,results.facets.terms.missing]],meta:"missing",color:'#aaa',opacity:0}); + // TODO: Hard coded to 0 for now. Solr faceting does not provide 'missing' value. + data: [[k, missing]], meta: "missing", color: '#aaa', opacity: 0 + }); + $scope.data.push({ + label: 'Other values', + // data:[[k+1,results.facets.terms.other]],meta:"other",color:'#444'}); + // TODO: Hard coded to 0 for now. Solr faceting does not provide 'other' value. + data: [[k + 1, $scope.hits - sum]], meta: "other", color: '#444' + }); + */ + + $scope.$emit('render'); + + $scope.sortingOrder = 'term'; + $scope.reverse = false; + $scope.filteredItems = []; + $scope.groupedItems = []; + $scope.itemsPerPage = 10; + $scope.pagedItems = []; + $scope.currentPage = 0; + + // init the filtered items + var searchMatch = function (haystack, needle) { + if (!needle) { + return true; + } + var res = haystack.toLowerCase().indexOf(needle.toLowerCase()) !== -1; + return res; + }; + + $scope.search = function () { + $scope.filteredItems = $filter('filter')($scope.data, function (item) { + if (searchMatch(item.term, $scope.query)) { + return true; + } + return false; + }); + if ($scope.sortingOrder !== '') { + $scope.filteredItems = $filter('orderBy')($scope.filteredItems, $scope.sortingOrder, $scope.reverse); + } + $scope.currentPage = 0; + $scope.groupToPages(); + }; + + + // calculate page in place + $scope.groupToPages = function () { + $scope.pagedItems = []; + + for (var i = 0; i < $scope.filteredItems.length; i++) { + if (i % $scope.itemsPerPage === 0) { + $scope.pagedItems[Math.floor(i / $scope.itemsPerPage)] = [ $scope.filteredItems[i] ]; + } else { + $scope.pagedItems[Math.floor(i / $scope.itemsPerPage)].push($scope.filteredItems[i]); + } + } + }; + + $scope.prevPage = function () { + if ($scope.currentPage > 0) { + $scope.currentPage--; + } + }; + + $scope.nextPage = function () { + if ($scope.currentPage < $scope.pagedItems.length - 1) { + $scope.currentPage++; + } + }; + + $scope.setPage = function () { + $scope.currentPage = this.n; + }; + + // functions have been describe process the data for display + $scope.range = function (size,start, end) { + var ret = []; + + if (size < end) { + end = size; + if(size<$scope.gap){ + start = 0; + }else{ + start = size-$scope.gap; + } + + } + for (var i = start; i < end; i++) { + ret.push(i); + } + return ret; + }; + $scope.search(); + + $scope.sort_by = function(newSortingOrder) { + if ($scope.sortingOrder === newSortingOrder){ + $scope.reverse = !$scope.reverse; + $scope.filteredItems.reverse(); + } + else { + $scope.reverse = true; + $scope.sortingOrder = newSortingOrder; + $scope.filteredItems = _.sortBy($scope.data, $scope.sortingOrder); + $scope.filteredItems.reverse(); + } + $scope.groupToPages(); + // icon setup + + $('th i').each(function(){ + // icon reset + $(this).removeClass().addClass('icon-sort'); + }); + if (!$scope.reverse) + { $('th.'+newSortingOrder+' i').removeClass().addClass('icon-chevron-up'); } + else + { $('th.'+newSortingOrder+' i').removeClass().addClass('icon-chevron-down');} + + }; + + }); + + } + }; + + $scope.set_refresh = function (state) { + $scope.refresh = state; + // if 'count' mode is selected, set decimal_points to zero automatically. + if ($scope.panel.mode === 'count') { + $scope.panel.decimal_points = 0; + } + }; + + $scope.close_edit = function() { + // Start refresh timer if enabled + if ($scope.panel.refresh.enable) { + $scope.set_timer($scope.panel.refresh.interval); + } + + if ($scope.refresh) { + // $scope.testMultivalued(); + $scope.get_data(); + } + $scope.refresh = false; + $scope.$emit('render'); + }; + + $scope.showMeta = function(term) { + if(_.isUndefined(term.meta)) { + return true; + } + if(term.meta === 'other' && !$scope.panel.other) { + return false; + } + if(term.meta === 'missing' && !$scope.panel.missing) { + return false; + } + return true; + }; + + + }); +}); diff --git a/src/app/panels/adTable/editor.html b/src/app/panels/adTable/editor.html new file mode 100644 index 000000000..ad6165e04 --- /dev/null +++ b/src/app/panels/adTable/editor.html @@ -0,0 +1,106 @@ +
+
+
+
Add Column
+ + +
+
+
+
Columns Click to remove
+ {{field}} +
+
+ +
Options
+
+
+
Header
+
+
+
Sorting
+
+
+
Sort
+ + + +
+
+
Font Size
+ +
+
+
Trim Factor Trim fields to this long divided by # of rows
+ +
+
+ +
+
+
Add Hyperlink Column Add a column that will contain hyperlinks to access another resources such as URLs.
+ +
+
+
Link Column Header
+ +
+
+
Display Links as Icons
+ +
+
+
Column for Links
+ +
+
+ +
+
+
Display Images Display images in column(s) that contain URLs to images.
+ +
+
+
Image Field(s) Comma separated list of fields that contain image URL.
+ +
+
+
Image Width For examples: auto, 85px, or 50%
+ +
+
+
Image Height For examples: auto, 85px, or 50%
+ +
+
+
+
Linkage Effective
+
+ +
+ +
+ diff --git a/src/app/panels/adTable/fields.html b/src/app/panels/adTable/fields.html new file mode 100644 index 000000000..5bfddbb57 --- /dev/null +++ b/src/app/panels/adTable/fields.html @@ -0,0 +1,19 @@ +
+
+
Add Field Add field to be shown on the fields list pane of the panel
+
+ + +
+
+
+
Fields Click to remove
+ {{field}} +
+
+
+
+
Calculate Top Field Values From All Data Select this if you want to calculate the top field values from all events in Solr using facet query. The fields that are shown on this page will be used for calculation. Notes that this can significantly impact your performance.
+ +
+
\ No newline at end of file diff --git a/src/app/panels/adTable/micropanel.html b/src/app/panels/adTable/micropanel.html new file mode 100644 index 000000000..99cc5993d --- /dev/null +++ b/src/app/panels/adTable/micropanel.html @@ -0,0 +1,45 @@ +× +

+ Micro Analysis of {{facet_label(micropanel.field)}} + + +
+ + {{micropanel.count|thousandSeparator}} events + + as + Groups / + Singles + + +

+ + + + + + + + + + + + + +
{{facet_label(micropanel.field)}}ActionCount
{{{true: "__blank__", false:field[0] }[field[0] == '' || field[0] == undefined]|tableTruncate:panel.trimFactor:3}} + + + + +
+ {{field[1]|thousandSeparator}} +
+
+
+
+ + diff --git a/src/app/panels/adTable/module.html b/src/app/panels/adTable/module.html new file mode 100644 index 000000000..f13723ab6 --- /dev/null +++ b/src/app/panels/adTable/module.html @@ -0,0 +1,116 @@ +
+ +
+
+ +
+ +
+ + +
+
+ + +
+
+ {{panel.offset + 1}}{{panel.offset}} to {{dashboard.numberWithCommas(panel.offset + data.slice(panel.offset,panel.offset+panel.size).length)}} + of {{dashboard.numberWithCommas(data.length)}} available for paging +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
message (select columns from the list to the left) + + + {{facet_label(field)}} + + + {{facet_label(field)}} + + {{panel.hyperlinkColumnHeader}}
{{event.kibana._source|stringify|tableTruncate:panel.trimFactor:1}}
+ + View: + Table / + JSON / + Raw + + + + + + + + + + + + + + +
FieldActionValue
{{key}} + + + +
+

+              

+            
+ +
+
+ + +
+
+ {{panel.offset + 1}}{{panel.offset}} to {{dashboard.numberWithCommas(panel.offset + data.slice(panel.offset,panel.offset+panel.size).length)}} + of {{dashboard.numberWithCommas(data.length)}} available for paging +
+
+ +
+
+
+
+
diff --git a/src/app/panels/adTable/module.js b/src/app/panels/adTable/module.js new file mode 100644 index 000000000..1bd63100b --- /dev/null +++ b/src/app/panels/adTable/module.js @@ -0,0 +1,507 @@ +/* + + ## Table + + ### Parameters + * size :: Number of events per page to show + * pages :: Number of pages to show. size * pages = number of cached events. + Bigger = more memory usage byh the browser + * offset :: Position from which to start in the array of hits + * sort :: An array with 2 elements. sort[0]: field, sort[1]: direction ('asc' or 'desc') + * style :: hash of css properties + * fields :: columns to show in table + * overflow :: 'height' or 'min-height' controls wether the row will expand (min-height) to + to fit the table, or if the table will scroll to fit the row (height) + * trimFactor :: If line is > this many characters, divided by the number of columns, trim it. + * sortable :: Allow sorting? + * spyable :: Show the 'eye' icon that reveals the last ES query for this panel + +*/ +define([ + 'angular', + 'app', + 'underscore', + 'kbn', + 'moment' + // 'text!./pagination.html', + // 'text!partials/querySelect.html' +], +function (angular, app, _, kbn, moment) { + 'use strict'; + + var module = angular.module('kibana.panels.adTable', []); + app.useModule(module); + module.controller('adTable', function($rootScope, $scope, fields, querySrv, dashboard, filterSrv, solrSrv) { + $scope.panelMeta = { + + editorTabs : [ + { + title:'Fields', + src: 'app/panels/adTable/fields.html' + }, + { + title:'Paging', + src: 'app/panels/adTable/pagination.html' + }, + { + title:'Queries', + src: 'app/partials/querySelect.html' + } + ], + exportfile: true, + status: "Stable", + description: "A paginated table of records matching your query (including any filters that may have been applied). Click on a row to expand it and review all of the fields associated with that document. Provides the capability to export your result set to CSV, XML or JSON for further processing using other systems." + }; + + // Set and populate defaults + var _d = { + status : "Stable", + queries : { + mode : 'all', + ids : [], + query : '*:*', + basic_query : '', + custom : '' + }, + size : 100, // Per page + pages : 5, // Pages available + offset : 0, + sort : [], // By default, sorting is turned off for performance reason + sortable: false, + group : "default", + style : {'font-size': '9pt'}, + overflow: 'min-height', + fields : [], + important_fields : [], + highlight : [], + header : true, + paging : true, + display:'block', + icon:"icon-caret-down", + + field_list: true, + linkage_id:'a', + trimFactor: 300, + normTimes : true, + spyable : true, + saveOption : 'json', + exportSize: 100, + exportAll: true, + displayLinkIcon: true, + imageFields : [], // fields to be displayed as + imgFieldWidth: 'auto', // width of (if enabled) + imgFieldHeight: '85px', // height of (if enabled) + show_queries: true, + maxNumCalcTopFields: 20, // Set the max number of fields for calculating top values + calcTopFieldValuesFromAllData: false // false: calculate top field values from $scope.data + // true: calculate from all data using Solr facet + }; + _.defaults($scope.panel,_d); + + $scope.percent = kbn.to_percent; + + $scope.init = function () { + $scope.Math = Math; + // Solr + $scope.sjs = $scope.sjs || sjsResource(dashboard.current.solr.server + dashboard.current.solr.core_name); // jshint ignore: line + $scope.$on('refresh',function(){$scope.get_data();}); + $scope.panel.exportSize = $scope.panel.size * $scope.panel.pages; + $scope.fields = fields; + $scope.get_data(); + }; + $scope.display=function() { + if($scope.panel.display==='none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; + $scope.toggle_micropanel = function(field,groups) { + var docs = _.map($scope.data,function(_d){return _d.kibana._source;}); + var topFieldValues = {}; + var totalcount = 0; + + if (!$scope.panel.calcTopFieldValuesFromAllData) { + topFieldValues = kbn.top_field_values(docs,field,10,groups); + totalcount = _.countBy(docs,function(doc){return _.contains(_.keys(doc),field);})['true']; + } else { + topFieldValues = solrSrv.getTopFieldValues(field); + totalcount = topFieldValues.totalcount; + } + + $scope.micropanel = { + field: field, + grouped: groups, + values : topFieldValues.counts, + hasArrays : topFieldValues.hasArrays, + related : kbn.get_related_fields(docs,field), + count: totalcount + }; + }; + + $scope.micropanelColor = function(index) { + var _c = ['bar-success','bar-warning','bar-danger','bar-info','bar-primary']; + return index > _c.length ? '' : _c[index]; + }; + + $scope.set_sort = function(field) { + if($scope.panel.sort[0] === field) { + $scope.panel.sort[1] = $scope.panel.sort[1] === 'asc' ? 'desc' : 'asc'; + } else { + $scope.panel.sort[0] = field; + } + $scope.get_data(); + }; + + $scope.toggle_field = function(field) { + if (_.indexOf($scope.panel.fields, field) > -1) { + $scope.panel.fields = _.without($scope.panel.fields, field); + } else if (_.indexOf(fields.list, field) > -1) { + $scope.panel.fields.push(field); + } else { + return; + } + }; + + // Toggle important field that will appear to the left of table panel + $scope.toggle_important_field = function(field) { + if (_.indexOf($scope.panel.important_fields,field) > -1) { + $scope.panel.important_fields = _.without($scope.panel.important_fields,field); + } else { + $scope.panel.important_fields.push(field); + } + }; + + $scope.toggle_highlight = function(field) { + if (_.indexOf($scope.panel.highlight,field) > -1) { + $scope.panel.highlight = _.without($scope.panel.highlight,field); + } else { + $scope.panel.highlight.push(field); + } + }; + + $scope.toggle_details = function(row) { + row.kibana.details = row.kibana.details ? false : true; + row.kibana.view = row.kibana.view || 'table'; + //row.kibana.details = !row.kibana.details ? $scope.without_kibana(row) : false; + }; + + $scope.page = function(page) { + $scope.panel.offset = page*$scope.panel.size; + $scope.get_data(); + }; + + $scope.build_search = function(field,value,negate) { + + var query; + // This needs to be abstracted somewhere + if (_.isArray(value)) { + // TODO: I don't think Solr has "AND" operator in query. + query = "(" + _.map(value, function (v) { + return angular.toJson(v); + }).join(" AND ") + ")"; + } else if (_.isUndefined(value)) { + query = '*:*'; + negate = !negate; + } else { + query = angular.toJson(value); + } + // TODO: Need to take a look here, not sure if need change. + filterSrv.set({type: 'field', field: field, query: query, mandate: (negate ? 'mustNot' : 'must')}); + + $scope.panel.offset = 0; + dashboard.current.linkage_id = $scope.panel.linkage_id; + dashboard.current.enable_linkage =false; + dashboard.refresh(); + + }; + + $scope.fieldExists = function(field,mandate) { + // TODO: Need to take a look here. + filterSrv.set({type:'exists',field:field,mandate:mandate}); + dashboard.refresh(); + }; + + $scope.get_data = function(segment,query_id) { + if(($scope.panel.linkage_id===dashboard.current.linkage_id)||dashboard.current.enable_linkage){ + $scope.panel.error = false; + delete $scope.panel.error; + + // Make sure we have everything for the request to complete + if (dashboard.indices.length === 0) { + return; + } + $scope.panelMeta.loading = true; + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + + // Calculate top field values + if ($scope.panel.calcTopFieldValuesFromAllData) { + // Make sure we are not calculating too much facet fields. + if ($scope.panel.important_fields.length > $scope.panel.maxNumCalcTopFields) { + alert('You cannot specify more than ' + $scope.panel.maxNumCalcTopFields + ' fields for the calculation. Please select less fields.'); + } else { + solrSrv.calcTopFieldValues($scope.panel.important_fields); + } + } + + // What this segment is for? => to select which indices to query. + var _segment = _.isUndefined(segment) ? 0 : segment; + $scope.segment = _segment; + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + var request = $scope.sjs.Request().indices(dashboard.indices[_segment]); + $scope.panel_request = request; + + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + } + if (dashboard.current.anomaly_fq) { + fq = fq + '&' + dashboard.current.anomaly_fq; + } + var query_size = $scope.panel.size * $scope.panel.pages; + var wt_json = '&wt=json'; + var rows_limit; + var sorting = ''; + + if ($scope.panel.sort[0] !== undefined && $scope.panel.sort[1] !== undefined && $scope.panel.sortable) { + sorting = '&sort=' + $scope.panel.sort[0] + ' ' + $scope.panel.sort[1]; + } + + // set the size of query result + if (query_size !== undefined && query_size !== 0) { + rows_limit = '&rows=' + query_size; + } else { // default + rows_limit = '&rows=25'; + } + + // Set the panel's query + $scope.panel.queries.basic_query = querySrv.getORquery() + fq + sorting; + $scope.panel.queries.query = $scope.panel.queries.basic_query + wt_json + rows_limit; + + // Set the additional custom query + if ($scope.panel.queries.custom != null) { + request = request.setQuery($scope.panel.queries.query + $scope.panel.queries.custom); + } else { + request = request.setQuery($scope.panel.queries.query); + } + + var results = request.doSearch(); + + // Populate scope when we have results + results.then(function (results) { + $scope.panel.offset = 0; + $scope.panelMeta.loading = false; + + if (_segment === 0) { + $scope.hits = 0; + $scope.data = []; + query_id = $scope.query_id = new Date().getTime(); + } else { + // Fix BUG with wrong total event count. + $scope.data = []; + } + + // Check for error and abort if found + if (!(_.isUndefined(results.error))) { + $scope.panel.error = $scope.parse_error(results.error.msg); // There's also results.error.code + return; + } + + // Check that we're still on the same query, if not stop + if ($scope.query_id === query_id) { + $scope.data = $scope.data.concat(_.map(results.response.docs, function (hit) { + var _h = _.clone(hit); + _h.kibana = { + _source: kbn.flatten_json(hit), + highlight: kbn.flatten_json(hit.highlight || {}) + }; + + return _h; + })); + + // Solr does not need to accumulate hits count because it can get total count + // from a single faceted query. + $scope.hits = results.response.numFound; + + // Keep only what we need for the set + $scope.data = $scope.data.slice(0, $scope.panel.size * $scope.panel.pages); + + // Dynamically display only non-empty fields on the field list (left side) + $scope.panel.important_fields = []; + _.each($scope.data, function (doc) { + $scope.panel.important_fields = _.union(_.keys(doc.kibana._source)); + }); + } else { + return; + } + + // If we're not sorting in reverse chrono order, query every index for + // size*pages results + // Otherwise, only get size*pages results then stop querying + if (($scope.data.length < $scope.panel.size * $scope.panel.pages || + !((_.contains(filterSrv.timeField(), $scope.panel.sort[0])) && $scope.panel.sort[1] === 'desc')) && + _segment + 1 < dashboard.indices.length) { + $scope.get_data(_segment + 1, $scope.query_id); + } + }); + } + }; + + $scope.exportfile = function(filetype) { + var omitHeader = '&omitHeader=true'; + var rows_limit = '&rows=' + ($scope.panel.exportSize || ($scope.panel.size * $scope.panel.pages)); + var fl = ''; + + if (! $scope.panel.exportAll) { + fl = '&fl='; + for(var i = 0; i < $scope.panel.fields.length; i++) { + fl += $scope.panel.fields[i] + (i !== $scope.panel.fields.length - 1 ? ',' : ''); + } + } + var exportQuery = $scope.panel.queries.basic_query + '&wt=' + filetype + omitHeader + rows_limit + fl; + var request = $scope.panel_request; + + if ($scope.panel.queries.custom != null) { + request = request.setQuery(exportQuery + $scope.panel.queries.custom); + } else { + request = request.setQuery(exportQuery); + } + + var response = request.doSearch(); + + response.then(function(response) { + kbn.download_response(response, filetype, "table"); + }); + }; + + $scope.facet_label = function(key) { + return filterSrv.translateLanguageKey("facet", key, dashboard.current); + }; + + $scope.populate_modal = function(request) { + $scope.inspector = angular.toJson(JSON.parse(request.toString()),true); + }; + + $scope.without_kibana = function (row) { + var _c = _.clone(row); + delete _c.kibana; + return _c; + }; + + $scope.set_refresh = function (state) { + $scope.refresh = state; + }; + + $scope.close_edit = function() { + if($scope.refresh) { + $scope.get_data(); + } + $scope.refresh = false; + }; + + $scope.locate = function(obj, path) { + path = path.split('.'); + var arrayPattern = /(.+)\[(\d+)\]/; + for (var i = 0; i < path.length; i++) { + var match = arrayPattern.exec(path[i]); + if (match) { + obj = obj[match[1]][parseInt(match[2],10)]; + } else { + obj = obj[path[i]]; + } + } + return obj; + }; + }); + + // This also escapes some xml sequences + module.filter('tableHighlight', function() { + return function(text) { + if (!_.isUndefined(text) && !_.isNull(text) && text.toString().length > 0) { + return text.toString(). + replace(/&/g, '&'). + replace(//g, '>'). + replace(/\r?\n/g, '
'). + replace(/@start-highlight@/g, ''). + replace(/@end-highlight@/g, ''); + } + return ''; + }; + }); + + module.filter('tableTruncate', function() { + return function(text,length,factor,field,imageFields) { + // If image field, then do not truncate, otherwise we will get invalid URIs. + if (typeof field !== 'undefined' && imageFields.length>0 && _.contains(imageFields, field)) { + return text; + } + + if (!_.isUndefined(text) && !_.isNull(text) && text.toString().length > 0) { + return text.length > length/factor ? text.substr(0,length/factor)+'...' : text; + } + return ''; + }; + }); + + module.filter('tableJson', function() { + var json; + return function(text,prettyLevel) { + if (!_.isUndefined(text) && !_.isNull(text) && text.toString().length > 0) { + json = angular.toJson(text,prettyLevel > 0 ? true : false); + json = json.replace(/&/g, '&').replace(//g, '>'); + if(prettyLevel > 1) { + /* jshint maxlen: false */ + json = json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) { + var cls = 'number'; + if (/^"/.test(match)) { + if (/:$/.test(match)) { + cls = 'key strong'; + } else { + cls = ''; + } + } else if (/true|false/.test(match)) { + cls = 'boolean'; + } else if (/null/.test(match)) { + cls = 'null'; + } + return '' + match + ''; + }); + } + return json; + } + return ''; + }; + }); + + // WIP + module.filter('tableFieldFormat', function(fields){ + return function(text,field,event,scope) { + var type; + if( + !_.isUndefined(fields.mapping[event._index]) && + !_.isUndefined(fields.mapping[event._index][event._type]) + ) { + type = fields.mapping[event._index][event._type][field]['type']; + if(type === 'date' && scope.panel.normTimes) { + return moment(text).format('YYYY-MM-DD HH:mm:ss'); + } + } + return text; + }; + }); + + // This filter will check the input field to see if it should be displayed as + module.filter('tableDisplayImageField', function() { + return function(data, field, imageFields, width, height) { + if (typeof field !== 'undefined' && imageFields.length>0 && _.contains(imageFields, field)) { + return ''; + } + return data; + }; + }); +}); diff --git a/src/app/panels/adTable/pagination.html b/src/app/panels/adTable/pagination.html new file mode 100644 index 000000000..a20526a6a --- /dev/null +++ b/src/app/panels/adTable/pagination.html @@ -0,0 +1,27 @@ +
+
+
Show Controls
+
+
+
Overflow
+ +
+
+
+
+
Per Page
+ +
+
+
 
+
+
+
+
Page limit
+ +
+
+
Pageable
+ = {{panel.size * panel.pages}} +
+
diff --git a/src/app/panels/apihistobar/editor.html b/src/app/panels/apihistobar/editor.html new file mode 100644 index 000000000..c5d2d280b --- /dev/null +++ b/src/app/panels/apihistobar/editor.html @@ -0,0 +1,122 @@ +
+
+ + + + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ + +
+ + +
+
+ In {{panel.mode}} mode the configured field must be a numeric type. +
+
+ + +
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+ +
+ + +
+
+ + +
+ + +
+ + +
+ + + +
+ + + +
Chart Settings
+ + + + +
+ + +
+ +
+
+ +
+
+ + +
+
+ + +
+ +
+ +
Tooltip Settings
+
+
+ + +
+
+ + +
+
+
+
Linkage Effective
+
+ +
+ +
diff --git a/src/app/panels/apihistobar/interval.js b/src/app/panels/apihistobar/interval.js new file mode 100644 index 000000000..673371fcf --- /dev/null +++ b/src/app/panels/apihistobar/interval.js @@ -0,0 +1,57 @@ +define([ + 'kbn' +], +function (kbn) { + 'use strict'; + + /** + * manages the interval logic + * @param {[type]} interval_string An interval string in the format '1m', '1y', etc + */ + function Interval(interval_string) { + this.string = interval_string; + + var info = kbn.describe_interval(interval_string); + this.type = info.type; + this.ms = info.sec * 1000 * info.count; + + // does the length of the interval change based on the current time? + if (this.type === 'y' || this.type === 'M') { + // we will just modify this time object rather that create a new one constantly + this.get = this.get_complex; + this.date = new Date(0); + } else { + this.get = this.get_simple; + } + } + + Interval.prototype = { + toString: function () { + return this.string; + }, + after: function(current_ms) { + return this.get(current_ms, 1); + }, + before: function (current_ms) { + return this.get(current_ms, -1); + }, + get_complex: function (current, delta) { + this.date.setTime(current); + switch(this.type) { + case 'M': + this.date.setUTCMonth(this.date.getUTCMonth() + delta); + break; + case 'y': + this.date.setUTCFullYear(this.date.getUTCFullYear() + delta); + break; + } + return this.date.getTime(); + }, + get_simple: function (current, delta) { + return current + (delta * this.ms); + } + }; + + return Interval; + +}); \ No newline at end of file diff --git a/src/app/panels/apihistobar/module.html b/src/app/panels/apihistobar/module.html new file mode 100644 index 000000000..42f2294a1 --- /dev/null +++ b/src/app/panels/apihistobar/module.html @@ -0,0 +1,133 @@ +
+ + +
+ +
+ + + View + + +
+ + + + + + + + + + + + + +
+ +
+
+ + + + + + +
{{term.label}}{{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}
+ + +
+ {{term.label}} ({{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}) +

+ +
+
{{data.length - 2}}
+ +
+ +
+ + + + + + +
{{term.label}}{{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}
+
+ +
+ +
+ + + + + + +
{{term.label}}{{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}
+ + +
+ {{term.label}} ({{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}) +

+ +
+ + + + + + +
+
+
diff --git a/src/app/panels/apihistobar/module.js b/src/app/panels/apihistobar/module.js new file mode 100644 index 000000000..d6df95b0d --- /dev/null +++ b/src/app/panels/apihistobar/module.js @@ -0,0 +1,777 @@ +/* + + ## Histogram + + ### Parameters + * auto_int :: Auto calculate data point interval? + * resolution :: If auto_int is enables, shoot for this many data points, rounding to + sane intervals + * interval :: Datapoint interval in elasticsearch date math format (eg 1d, 1w, 1y, 5y) + * fill :: Only applies to line charts. Level of area shading from 0-10 + * linewidth :: Only applies to line charts. How thick the line should be in pixels + While the editor only exposes 0-10, this can be any numeric value. + Set to 0 and you'll get something like a scatter plot + * timezone :: This isn't totally functional yet. Currently only supports browser and utc. + browser will adjust the x-axis labels to match the timezone of the user's + browser + * spyable :: Dislay the 'eye' icon that show the last elasticsearch query + * zoomlinks :: Show the zoom links? + * bars :: Show bars in the chart + * stack :: Stack multiple queries. This generally a crappy way to represent things. + You probably should just use a line chart without histobar + * points :: Should circles at the data points on the chart + * lines :: Line chart? Sweet. + * legend :: Show the legend? + * x-axis :: Show x-axis labels and grid lines + * y-axis :: Show y-axis labels and grid lines + * interactive :: Allow drag to select time range + +*/ +define([ + 'angular', + 'app', + 'jquery', + 'underscore', + 'kbn', + 'moment', + './timeSeries', + 'echarts-wordcloud' + + +], +function (angular, app, $, _, kbn, moment, timeSeries) { + 'use strict'; + var module = angular.module('kibana.panels.apihistobar', []); + app.useModule(module); + + module.controller('apihistobar', function($scope, $q, querySrv, dashboard, filterSrv) { + var _d; + $scope.panelMeta = { + + editorTabs : [ + { + title:'Queries', + src:'app/partials/querySelect.html' + } + ], + status : "Stable", + description : "A bucketed time series chart of the current query, including all applied time and non-time filters, when used in count mode. Uses Solr’s facet.range query parameters. In values mode, it plots the value of a specific field over time, and allows the user to group field values by a second field." + }; + + // Set and populate defaults + _d = { + mode: 'value', + queries: { + mode: 'all', + ids: [], + query: '*:*', + custom: '' + }, + max_rows: 100000, // maximum number of rows returned from Solr (also use this for group.limit to simplify UI setting) + reverse: 0, + segment: 4, + + threshold_first: 300, + threshold_second: 400, + threshold_third: 3000, + group_field: null, + auto_int: true, + linkage_id:'a', + defaulttimestamp:true, + display:'block', + icon:"icon-caret-down", + area:false, + total_first: '%', + fontsize: 12, + isEN:false, + another:false, + field_color: '#2ce41b', + resolution: 100, + value_sort: 'rs_timestamp', + interval: '5m', + intervals: ['auto', '1s', '1m', '5m', '10m', '30m', '1h', '3h', '12h', '1d', '1w', '1M', '1y'], + fill: 0, + linewidth: 3, + chart: 'histobar', + chartColors: ['#f48a52', '#f4d352', '#ccf452', '#8cf452', '#3cee2b', '#f467d8', '#1a93f9', '#2fd7ee'], + timezone: 'browser', // browser, utc or a standard timezone + spyable: true, + linkage: false, + value_category: 'api_s', + zoomlinks: true, + bars: true, + average: false, + label: true, + points: false, + lines: false, + lines_smooth: false, // Enable 'smooth line' mode by removing zero values from the plot. + legend: true, + 'x-axis': true, + 'y-axis': true, + percentage: false, + interactive: true, + options: false, + show_queries: true, + tooltip: { + value_type: 'cumulative', + query_as_alias: false + } + }; + + _.defaults($scope.panel,_d); + + $scope.init = function() { + // Hide view options by default + $scope.options = false; + $scope.$on('refresh',function(){ + $scope.get_data(); + }); + + $scope.get_data(); + + }; + + $scope.set_interval = function(interval) { + if(interval !== 'auto') { + $scope.panel.auto_int = false; + $scope.panel.interval = interval; + } else { + $scope.panel.auto_int = true; + } + }; + + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; + + $scope.interval_label = function(interval) { + return $scope.panel.auto_int && interval === $scope.panel.interval ? interval+" (auto)" : interval; + }; + + /** + * The time range effecting the panel + * @return {[type]} [description] + */ + $scope.get_time_range = function () { + var range = $scope.range = filterSrv.timeRange('min'); + return range; + }; + + $scope.get_interval = function () { + var interval = $scope.panel.interval, + range; + if ($scope.panel.auto_int) { + range = $scope.get_time_range(); + if (range) { + interval = kbn.secondsToHms( + kbn.calculate_interval(range.from, range.to, $scope.panel.resolution, 0) / 1000 + ); + } + } + $scope.panel.interval = interval || '10m'; + return $scope.panel.interval; + }; + + /** + * Fetch the data for a chunk of a queries results. Multiple segments occur when several indicies + * need to be consulted (like timestamped logstash indicies) + * + * The results of this function are stored on the scope's data property. This property will be an + * array of objects with the properties info, time_series, and hits. These objects are used in the + * render_panel function to create the historgram. + * + * !!! Solr does not need to fetch the data in chunk because it uses a facet search and retrieve + * !!! all events from a single query. + * + * @param {number} segment The segment count, (0 based) + * @param {number} query_id The id of the query, generated on the first run and passed back when + * this call is made recursively for more segments + */ + $scope.get_data = function(segment, query_id) { + if(($scope.panel.linkage_id === dashboard.current.linkage_id)||dashboard.current.enable_linkage){ + + if (_.isUndefined(segment)) { + segment = 0; + } + delete $scope.panel.error; + + // Make sure we have everything for the request to complete + if (dashboard.indices.length === 0) { + return; + } + var _range = $scope.get_time_range(); + var _interval = $scope.get_interval(_range); + + if ($scope.panel.auto_int) { + $scope.panel.interval = kbn.secondsToHms( + kbn.calculate_interval(_range.from, _range.to, $scope.panel.resolution, 0) / 1000); + } + + $scope.panelMeta.loading = true; + + // Solr + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + var request = $scope.sjs.Request().indices(dashboard.indices[segment]); + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + + + $scope.panel.queries.query = ""; + // Build the query + _.each($scope.panel.queries.ids, function (id) { + var query = $scope.sjs.FilteredQuery( + querySrv.getEjsObj(id), + filterSrv.getBoolFilter(filterSrv.ids) + ); + + var facet = $scope.sjs.DateHistogramFacet(id); + if ($scope.panel.mode === 'count' || $scope.panel.mode === 'counts') { + facet = facet.field(filterSrv.getTimeField()); + } else { + if (_.isNull($scope.panel.value_field)) { + $scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified"; + return; + } + facet = facet.keyField(filterSrv.getTimeField()).valueField($scope.panel.value_field); + } + facet = facet.interval(_interval).facetFilter($scope.sjs.QueryFilter(query)); + request = request.facet(facet).size(0); + + }); + + // Populate the inspector panel + $scope.populate_modal(request); + + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + } + if (!$scope.panel.defaulttimestamp) { + fq = fq.replace(filterSrv.getTimeField(), $scope.panel.value_sort); + } + var time_field = $scope.panel.defaulttimestamp ? filterSrv.getTimeField() : $scope.panel.value_sort; + var start_time = filterSrv.getStartTime(); + var end_time = filterSrv.getEndTime(); + + // facet.range.end does NOT accept * as a value, need to convert it to NOW + if (end_time === '*') { + end_time = 'NOW'; + } + + var wt_json = '&wt=json'; + var sort_s = '&sort=' + $scope.panel.value_sort + '%20asc'; + var rows_limit = '&rows=0'; // for histogram, we do not need the actual response doc, so set rows=0 + var facet_gap = $scope.sjs.convertFacetGap($scope.panel.interval); + var facet = '&facet=true' + + '&facet.range=' + time_field + + '&facet.range.start=' + start_time + + '&facet.range.end=' + end_time + + '&facet.range.gap=' + facet_gap; + var values_mode_query = ''; + + // For mode = value + if ($scope.panel.mode === 'values' || $scope.panel.mode === 'value') { + if (!$scope.panel.value_field) { + $scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified"; + return; + } + values_mode_query = '&fl=' + time_field + ' ' + $scope.panel.value_field + ' ' + $scope.panel.value_category; + + rows_limit = '&rows=' + $scope.panel.max_rows; + facet = ''; + + // if Group By Field is specified + if ($scope.panel.group_field) { + values_mode_query += '&group=true&group.field=' + $scope.panel.group_field + '&group.limit=' + $scope.panel.max_rows; + } + } + + var mypromises = []; + if ($scope.panel.mode === 'value' || $scope.panel.mode === 'counts') { + var arr_id = [0]; + _.each(arr_id, function () { + var temp_q = 'q=' + $scope.panel.value_field + '%3A%5B' + '*' + '%20TO%20' + '*' + '%5D' + wt_json + sort_s + rows_limit + fq + facet + values_mode_query; + + $scope.panel.queries.query += temp_q + "\n"; + if ($scope.panel.queries.custom !== null) { + request = request.setQuery(temp_q + $scope.panel.queries.custom); + } else { + request = request.setQuery(temp_q); + } + mypromises.push(request.doSearch()); + }); + } + $scope.data = []; + + if (dashboard.current.services.query.ids.length >= 1) { + $q.all(mypromises).then(function (results) { + $scope.panelMeta.loading = false; + if (segment === 0) { + $scope.hits = 0; + $scope.data = []; + query_id = $scope.query_id = new Date().getTime(); + } + // Convert facet ids to numbers + // var facetIds = _.map(_.keys(results.facets),function(k){return parseInt(k, 10);}); + //var facetIds = [0]; // Need to fix this + + // Make sure we're still on the same query/queries + // TODO: We probably DON'T NEED THIS unless we have to support multiple queries in query module. + // if ($scope.query_id === query_id && _.difference(facetIds, $scope.panel.queries.ids).length === 0) { + var i = 0, + time_series, + hits; + + _.each(arr_id, function (id, index) { + // Check for error and abort if found + if (!(_.isUndefined(results[index].error))) { + $scope.panel.error = $scope.parse_error(results[index].error.msg); + return; + } + // we need to initialize the data variable on the first run, + // and when we are working on the first segment of the data. + if (_.isUndefined($scope.data[i]) || segment === 0) { + time_series = new timeSeries.ZeroFilled({ + interval: _interval, + start_date: _range && _range.from, + end_date: _range && _range.to, + fill_style: 'minimal' + }); + hits = 0; + } else { + time_series = $scope.data[i].time_series; + // Bug fix for wrong event count: + // Solr don't need to accumulate hits count since it can get total count from facet query. + // Therefore, I need to set hits and $scope.hits to zero. + // hits = $scope.data[i].hits; + hits = 0; + $scope.hits = 0; + } + // Solr facet counts response is in one big array. + // So no need to get each segment like Elasticsearch does. + $scope.data[i] = results[index].response.docs; + i++; + }); + // Tell the histogram directive to render. + $scope.$emit('render'); + // } + }); + } + } + }; + + // function $scope.zoom + // factor :: Zoom factor, so 0.5 = cuts timespan in half, 2 doubles timespan + $scope.zoom = function(factor) { + var _range = filterSrv.timeRange('min'); + var _timespan = (_range.to.valueOf() - _range.from.valueOf()); + var _center = _range.to.valueOf() - _timespan/2; + + var _to = (_center + (_timespan*factor)/2); + var _from = (_center - (_timespan*factor)/2); + + // If we're not already looking into the future, don't. + if(_to > Date.now() && _range.to < Date.now()) { + var _offset = _to - Date.now(); + _from = _from - _offset; + _to = Date.now(); + } + + var time_field = filterSrv.getTimeField(); + if(factor > 1) { + filterSrv.removeByType('time'); + } + + filterSrv.set({ + type:'time', + from:moment.utc(_from).toDate(), + to:moment.utc(_to).toDate(), + field:time_field + }); + + dashboard.refresh(); + }; + + // I really don't like this function, too much dom manip. Break out into directive? + $scope.populate_modal = function(request) { + $scope.inspector = angular.toJson(JSON.parse(request.toString()),true); + }; + + $scope.set_refresh = function (state) { + $scope.refresh = state; + }; + + $scope.close_edit = function() { + if($scope.refresh) { + $scope.get_data(); + } + $scope.refresh = false; + $scope.$emit('render'); + }; + + $scope.render = function() { + $scope.$emit('render'); + }; + + }); + + module.directive('apihistobarChart', function( querySrv,dashboard,filterSrv) { + return { + restrict: 'A', + link: function(scope, elem) { + var myChart; + // Receive render events + scope.$on('render',function(){ + render_panel(); + }); + + // Re-render if the window is resized + angular.element(window).bind('resize', function(){ + render_panel(); + }); + + // Function for rendering panel + function render_panel() { + var chartData; + var colors = []; + + // IE doesn't work without this + elem.css({height:scope.panel.height||scope.row.height}); + + // Make a clone we can operate on. + + chartData = _.clone(scope.data); + chartData = scope.panel.missing ? chartData : + _.without(chartData,_.findWhere(chartData,{meta:'missing'})); + chartData = scope.panel.other ? chartData : + _.without(chartData,_.findWhere(chartData,{meta:'other'})); + + if (filterSrv.idsByTypeAndField('terms',scope.panel.field).length > 0) { + colors.push(scope.panel.lastColor); + } else { + colors = scope.panel.chartColors; + } + var selecttime = []; + var rs_timestamp = []; + var valuedata= []; + var secondtime ; + var maxdata= 0; + var sum_data = 0; + var sum_normal = 0; + var sum_risk = 0; + var sum_warning = 0; + + + Date.prototype.pattern = function (fmt) { + var o = { + "M+" : this.getMonth() + 1, //月份 + "d+" : this.getDate(), //æ—¥ + "h+" : this.getHours(), //å°æ—¶ + "H+" : this.getHours(), //å°æ—¶ + "m+" : this.getMinutes(), //分 + "s+" : this.getSeconds(), //ç§’ + "q+" : Math.floor((this.getMonth() + 3) / 3), //季度 + "S" : this.getMilliseconds() //毫秒 + }; + var week = { + "0" : "/u65e5", + "1" : "/u4e00", + "2" : "/u4e8c", + "3" : "/u4e09", + "4" : "/u56db", + "5" : "/u4e94", + "6" : "/u516d" + }; + if (/(y+)/.test(fmt)) { + fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length)); + } + if (/(E+)/.test(fmt)) { + fmt = fmt.replace(RegExp.$1, ((RegExp.$1.length > 1) ? (RegExp.$1.length > 2 ? "/u661f/u671f" : "/u5468") : "") + week[this.getDay() + ""]); + } + for (var k in o) { + if (new RegExp("(" + k + ")").test(fmt)) { + fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); + } + } + return fmt; + }; + + for (var i =0;iscope.panel.threshold_second){ + sum_risk++; + // valuedata[i] ={name:"Risk",value:chartData[0][i][scope.panel.value_field],itemStyle:{normal:{color:'#c55249'}}}; + }else if(chartData[0][i][scope.panel.value_field]scope.panel.threshold_second){ + if(scope.panel.another){ myWarn = "Risk";}else{ + myWarn = "Error"; + } + }else if(warn'+"API State: "+myWarn+'
'+"API duration: "+warn+'
'+"Time: "+params[0].name; + }else { + res = "API Name: " + params[0].data.name + '
' + "API State: " + myWarn+'
'+"Time: "+params[0].name; + } + return res; + }, + }, + legend: { + data:['aa'] + }, + toolbox: { + show : true, + top:'5%', + feature : { + dataZoom: { + yAxisIndex: 'none' + }, + dataView : {show: true, readOnly: false}, + magicType : {show: true, type: ['line', 'bar']} + + + } + }, + visualMap: { + show:scope.panel.legend, + top: 'top', + padding:0, + textGap:1, + textStyle:{ + color:labelcolor?'#DCDCDC':'#696969', + fontSize:scope.panel.fontSize + }, + itemWidth:10, + itemHeight:8, + orient:isspan?'vertical':'horizontal', + pieces: [{ + gt: 0, + lte: scope.panel.threshold_first, + label:scope.panel.another?('Normal(0~'+scope.panel.threshold_first+" "+sum_normal+'%)'):('Normal('+sum_normal+'%)'), + color: '#1a93f9' + }, { + gt: scope.panel.threshold_first, + lte: scope.panel.threshold_second, + label:scope.panel.another?('Warning('+scope.panel.threshold_first+'~'+scope.panel.threshold_second+" "+sum_warning+'%)'):('TimeOut('+sum_warning+'%)'), + color: '#f48a52' + }, { + gt: scope.panel.threshold_second, + label:scope.panel.another?('Risk(>'+scope.panel.threshold_second+" "+sum_risk+'%)'):('Error('+sum_risk+'%)'), + color: '#ec4653' + }], + outOfRange: { + color: '#999' + } + }, + calculable : true, + xAxis : [ + { + type : 'category', + axisLine: {onZero: true}, + axisLabel:{ + textStyle:{ + color:labelcolor?'#DCDCDC':'#696969' + } + }, + data : rs_timestamp + } + ], + yAxis : [ + { + type : 'value', + nameTextStyle:{ + color:labelcolor?'#DCDCDC':'#696969' + }, + axisLine:{ + lineStyle:{ + color:'#46474C' + } + }, + splitLine:{ + lineStyle:{ + color:['#46474C'] + } + }, + axisLabel:{ + textStyle:{ + color:labelcolor?'#DCDCDC':'#696969' + } + } + } + ], + series : [ + { + name:scope.panel.value_field, + type:scope.panel.bars?'bar':'line', + data:valuedata, + smooth: true, + areaStyle: scope.panel.area?{normal: {opacity:0.6}}:'', + //markPoint : { + //data : [ + //{type : 'max', name: scope.panel.isEN?'Max':'最大值'}, + //{type : 'min', name: scope.panel.isEN?'Min':'最å°å€¼'} + // ] + // }, + markLine : scope.panel.average?{ + label:{ + normal:{ + show:true, + position:'start' + } + }, + lineStyle:{ + normal:{ + color:scope.panel.field_color + } + }, + data : [ + {type : 'average', name:scope.panel.isEN?'Average':'å¹³å‡å€¼'} + ] + }:'' + } + ] +}; + + + // 使用刚指定的é…ç½®é¡¹å’Œæ•°æ®æ˜¾ç¤ºå›¾è¡¨ã€‚ + myChart.setOption(option); + + myChart.on('datazoom', function (params) { + + if (scope.panel.linkage) { + filterSrv.set({ + type: 'time', + // from : moment.utc(ranges.xaxis.from), + // to : moment.utc(ranges.xaxis.to), + from: moment.utc(selecttime[params.batch[0].startValue]).toDate(), + to: moment.utc(selecttime[params.batch[0].endValue]).toDate(), + field: filterSrv.getTimeField() + }); + dashboard.current.linkage_id = $scope.panel.linkage_id; + dashboard.current.enable_linkage = false; + dashboard.refresh(); + } + + }); + + } + + // Populate legend + + + } catch(e) { + elem.text(e); + } + }); + } + + } + }; + }); + +}); diff --git a/src/app/panels/apihistobar/timeSeries.js b/src/app/panels/apihistobar/timeSeries.js new file mode 100644 index 000000000..96054fa7d --- /dev/null +++ b/src/app/panels/apihistobar/timeSeries.js @@ -0,0 +1,179 @@ +define([ + 'underscore', + './interval' +], +function (_, Interval) { + 'use strict'; + + var ts = {}; + + // map compatable parseInt + function base10Int(val) { + return parseInt(val, 10); + } + + // trim the ms off of a time, but return it with empty ms. + function getDatesTime(date) { + return Math.floor(date.getTime() / 1000)*1000; + } + + /** + * Certain graphs require 0 entries to be specified for them to render + * properly (like the line graph). So with this we will caluclate all of + * the expected time measurements, and fill the missing ones in with 0 + * @param {object} opts An object specifying some/all of the options + * + * OPTIONS: + * @opt {string} interval The interval notion describing the expected spacing between + * each data point. + * @opt {date} start_date (optional) The start point for the time series, setting this and the + * end_date will ensure that the series streches to resemble the entire + * expected result + * @opt {date} end_date (optional) The end point for the time series, see start_date + * @opt {string} fill_style Either "minimal", or "all" describing the strategy used to zero-fill + * the series. + */ + ts.ZeroFilled = function (opts) { + opts = _.defaults(opts, { + interval: '10m', + start_date: null, + end_date: null, + fill_style: 'minimal' + }); + + // the expected differenece between readings. + this.interval = new Interval(opts.interval); + + // will keep all values here, keyed by their time + this._data = {}; + this.start_time = opts.start_date && getDatesTime(opts.start_date); + this.end_time = opts.end_date && getDatesTime(opts.end_date); + this.opts = opts; + }; + + /** + * Add a row + * @param {int} time The time for the value, in + * @param {any} value The value at this time + */ + ts.ZeroFilled.prototype.addValue = function (time, value) { + if (time instanceof Date) { + time = getDatesTime(time); + } else { + time = base10Int(time); + } + if (!isNaN(time)) { + this._data[time] = (_.isUndefined(value) ? 0 : value); + } + this._cached_times = null; + }; + + /** + * Get an array of the times that have been explicitly set in the series + * @param {array} include (optional) list of timestamps to include in the response + * @return {array} An array of integer times. + */ + ts.ZeroFilled.prototype.getOrderedTimes = function (include) { + var times = _.map(_.keys(this._data), base10Int); + if (_.isArray(include)) { + times = times.concat(include); + } + return _.uniq(times.sort(function (a, b) { + // decending numeric sort + return a - b; + }), true); + }; + + /** + * return the rows in the format: + * [ [time, value], [time, value], ... ] + * + * Heavy lifting is done by _get(Min|All)FlotPairs() + * @param {array} required_times An array of timestamps that must be in the resulting pairs + * @return {array} + */ + ts.ZeroFilled.prototype.getFlotPairs = function (required_times) { + var times = this.getOrderedTimes(required_times), + strategy, + pairs; + + if(this.opts.fill_style === 'all') { + strategy = this._getAllFlotPairs; + } else { + strategy = this._getMinFlotPairs; + } + + pairs = _.reduce( + times, // what + strategy, // how + [], // where + this // context + ); + + // if the first or last pair is inside either the start or end time, + // add those times to the series with null values so the graph will stretch to contain them. + if (this.start_time && (pairs.length === 0 || pairs[0][0] > this.start_time)) { + pairs.unshift([this.start_time, null]); + } + if (this.end_time && (pairs.length === 0 || pairs[pairs.length - 1][0] < this.end_time)) { + pairs.push([this.end_time, null]); + } + + return pairs; + }; + + /** + * ** called as a reduce stragegy in getFlotPairs() ** + * Fill zero's on either side of the current time, unless there is already a measurement there or + * we are looking at an edge. + * @return {array} An array of points to plot with flot + */ + ts.ZeroFilled.prototype._getMinFlotPairs = function (result, time, i, times) { + var next, expected_next, prev, expected_prev; + + // check for previous measurement + if (i > 0) { + prev = times[i - 1]; + expected_prev = this.interval.before(time); + if (prev < expected_prev) { + result.push([expected_prev, 0]); + } + } + + // add the current time + result.push([ time, this._data[time] || 0 ]); + + // check for next measurement + if (times.length > i) { + next = times[i + 1]; + expected_next = this.interval.after(time); + if (next > expected_next) { + result.push([expected_next, 0]); + } + } + + return result; + }; + + /** + * ** called as a reduce stragegy in getFlotPairs() ** + * Fill zero's to the right of each time, until the next measurement is reached or we are at the + * last measurement + * @return {array} An array of points to plot with flot + */ + ts.ZeroFilled.prototype._getAllFlotPairs = function (result, time, i, times) { + var next, expected_next; + + result.push([ times[i], this._data[times[i]] || 0 ]); + next = times[i + 1]; + expected_next = this.interval.after(time); + for(; times.length > i && next > expected_next; expected_next = this.interval.after(expected_next)) { + result.push([expected_next, 0]); + } + + return result; + }; + + + return ts; +}); \ No newline at end of file diff --git a/src/app/panels/apihistogram/editor.html b/src/app/panels/apihistogram/editor.html new file mode 100644 index 000000000..536e7440d --- /dev/null +++ b/src/app/panels/apihistogram/editor.html @@ -0,0 +1,134 @@ +
+
+ + + + +
+
+ + +
+
+ + +
+
+ In {{panel.mode}} mode the configured field must be a numeric type. +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+ +
+ +
Chart Settings
+
+
+
+
+
+
+ + +
+
+
+
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ + +
+
+ +
Tooltip Settings
+
+
+ + +
+
+ + +
+
+
+
Linkage Effective
+
+ +
+ +
diff --git a/src/app/panels/apihistogram/interval.js b/src/app/panels/apihistogram/interval.js new file mode 100644 index 000000000..673371fcf --- /dev/null +++ b/src/app/panels/apihistogram/interval.js @@ -0,0 +1,57 @@ +define([ + 'kbn' +], +function (kbn) { + 'use strict'; + + /** + * manages the interval logic + * @param {[type]} interval_string An interval string in the format '1m', '1y', etc + */ + function Interval(interval_string) { + this.string = interval_string; + + var info = kbn.describe_interval(interval_string); + this.type = info.type; + this.ms = info.sec * 1000 * info.count; + + // does the length of the interval change based on the current time? + if (this.type === 'y' || this.type === 'M') { + // we will just modify this time object rather that create a new one constantly + this.get = this.get_complex; + this.date = new Date(0); + } else { + this.get = this.get_simple; + } + } + + Interval.prototype = { + toString: function () { + return this.string; + }, + after: function(current_ms) { + return this.get(current_ms, 1); + }, + before: function (current_ms) { + return this.get(current_ms, -1); + }, + get_complex: function (current, delta) { + this.date.setTime(current); + switch(this.type) { + case 'M': + this.date.setUTCMonth(this.date.getUTCMonth() + delta); + break; + case 'y': + this.date.setUTCFullYear(this.date.getUTCFullYear() + delta); + break; + } + return this.date.getTime(); + }, + get_simple: function (current, delta) { + return current + (delta * this.ms); + } + }; + + return Interval; + +}); \ No newline at end of file diff --git a/src/app/panels/apihistogram/module.html b/src/app/panels/apihistogram/module.html new file mode 100644 index 000000000..c0320719a --- /dev/null +++ b/src/app/panels/apihistogram/module.html @@ -0,0 +1,96 @@ +
+ +
+
+ + + View + |  + + + + Zoom Out |  + + + + {{series.info.alias.substring(0,series.info.alias.length-2)}} ({{series.hits}}{{series.info.alias.substr(-2)}}) + + +
+
+ + + + + + + + + + + + + +
+ +
+
+ + + +
+
+
+
+
diff --git a/src/app/panels/apihistogram/module.js b/src/app/panels/apihistogram/module.js new file mode 100644 index 000000000..536324c86 --- /dev/null +++ b/src/app/panels/apihistogram/module.js @@ -0,0 +1,912 @@ +/* + + ## Histogram + + ### Parameters + * auto_int :: Auto calculate data point interval? + * resolution :: If auto_int is enables, shoot for this many data points, rounding to + sane intervals + * interval :: Datapoint interval in elasticsearch date math format (eg 1d, 1w, 1y, 5y) + * fill :: Only applies to line charts. Level of area shading from 0-10 + * linewidth :: Only applies to line charts. How thick the line should be in pixels + While the editor only exposes 0-10, this can be any numeric value. + Set to 0 and you'll get something like a scatter plot + * timezone :: This isn't totally functional yet. Currently only supports browser and utc. + browser will adjust the x-axis labels to match the timezone of the user's + browser + * spyable :: Dislay the 'eye' icon that show the last elasticsearch query + * zoomlinks :: Show the zoom links? + * bars :: Show bars in the chart + * stack :: Stack multiple queries. This generally a crappy way to represent things. + You probably should just use a line chart without stacking + * points :: Should circles at the data points on the chart + * lines :: Line chart? Sweet. + * legend :: Show the legend? + * x-axis :: Show x-axis labels and grid lines + * y-axis :: Show y-axis labels and grid lines + * interactive :: Allow drag to select time range + +*/ +define([ + 'angular', + 'app', + 'jquery', + 'underscore', + 'kbn', + 'moment', + './timeSeries', + + 'jquery.flot', + 'jquery.flot.pie', + 'jquery.flot.selection', + 'jquery.flot.time', + 'jquery.flot.stack', + 'jquery.flot.stackpercent', + 'jquery.flot.axislabels' +], +function (angular, app, $, _, kbn, moment, timeSeries) { + 'use strict'; + + var module = angular.module('kibana.panels.apihistogram', []); + app.useModule(module); + + module.controller('apihistogram', function($scope, $q, querySrv, dashboard, filterSrv) { + $scope.panelMeta = { + + editorTabs : [ + { + title:'Queries', + src:'app/partials/querySelect.html' + } + ], + status : "Stable", + description : "A bucketed time series chart of the current query, including all applied time and non-time filters, when used in count mode. Uses Solr’s facet.range query parameters. In values mode, it plots the value of a specific field over time, and allows the user to group field values by a second field." + }; + + // Set and populate defaults + var _d = { + mode : 'count', + queries : { + mode : 'all', + ids : [], + query : '*:*', + custom : '' + }, + max_rows : 100000, // maximum number of rows returned from Solr (also use this for group.limit to simplify UI setting) + reverse :0, + segment :3, + linkage_id:'a', + threshold_first:1000, + threshold_second:2000, + threshold_third:3000, + value_field : null, + group_field : null, + auto_int : true, + resolution : 100, + interval : '5m', + intervals : ['auto','1s','1m','5m','10m','30m','1h','3h','12h','1d','1w','1M','1y'], + fill : 0, + linewidth : 3, + timezone : 'browser', // browser, utc or a standard timezone + spyable : true, + zoomlinks : true, + bars : true, + stack : true, + points : false, + display:'block', + icon:"icon-caret-down", + lines : false, + lines_smooth: false, // Enable 'smooth line' mode by removing zero values from the plot. + legend : true, + 'x-axis' : true, + 'y-axis' : true, + percentage : false, + interactive : true, + options : true, + show_queries:true, + tooltip : { + value_type: 'cumulative', + query_as_alias: false + } + }; + + _.defaults($scope.panel,_d); + + $scope.init = function() { + // Hide view options by default + $scope.options = false; + $scope.$on('refresh',function(){ + $scope.get_data(); + }); + + $scope.get_data(); + + }; + + $scope.set_interval = function(interval) { + if(interval !== 'auto') { + $scope.panel.auto_int = false; + $scope.panel.interval = interval; + } else { + $scope.panel.auto_int = true; + } + }; + + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; + + $scope.interval_label = function(interval) { + return $scope.panel.auto_int && interval === $scope.panel.interval ? interval+" (auto)" : interval; + }; + + /** + * The time range effecting the panel + * @return {[type]} [description] + */ + $scope.get_time_range = function () { + var range = $scope.range = filterSrv.timeRange('min'); + return range; + }; + + $scope.get_interval = function () { + var interval = $scope.panel.interval, + range; + if ($scope.panel.auto_int) { + range = $scope.get_time_range(); + if (range) { + interval = kbn.secondsToHms( + kbn.calculate_interval(range.from, range.to, $scope.panel.resolution, 0) / 1000 + ); + } + } + $scope.panel.interval = interval || '10m'; + return $scope.panel.interval; + }; + + /** + * Fetch the data for a chunk of a queries results. Multiple segments occur when several indicies + * need to be consulted (like timestamped logstash indicies) + * + * The results of this function are stored on the scope's data property. This property will be an + * array of objects with the properties info, time_series, and hits. These objects are used in the + * render_panel function to create the historgram. + * + * !!! Solr does not need to fetch the data in chunk because it uses a facet search and retrieve + * !!! all events from a single query. + * + * @param {number} segment The segment count, (0 based) + * @param {number} query_id The id of the query, generated on the first run and passed back when + * this call is made recursively for more segments + */ + $scope.get_data = function(segment, query_id) { + if(($scope.panel.linkage_id === dashboard.current.linkage_id)||dashboard.current.enable_linkage){ + if (_.isUndefined(segment)) { + segment = 0; + } + delete $scope.panel.error; + + // Make sure we have everything for the request to complete + if (dashboard.indices.length === 0) { + return; + } + var _range = $scope.get_time_range(); + var _interval = $scope.get_interval(_range); + + if ($scope.panel.auto_int) { + $scope.panel.interval = kbn.secondsToHms( + kbn.calculate_interval(_range.from, _range.to, $scope.panel.resolution, 0) / 1000); + } + + $scope.panelMeta.loading = true; + + // Solr + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + var request = $scope.sjs.Request().indices(dashboard.indices[segment]); + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + + + $scope.panel.queries.query = ""; + // Build the query + _.each($scope.panel.queries.ids, function (id) { + var query = $scope.sjs.FilteredQuery( + querySrv.getEjsObj(id), + filterSrv.getBoolFilter(filterSrv.ids) + ); + + var facet = $scope.sjs.DateHistogramFacet(id); + if ($scope.panel.mode === 'count' || $scope.panel.mode === 'counts') { + facet = facet.field(filterSrv.getTimeField()); + } else { + if (_.isNull($scope.panel.value_field)) { + $scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified"; + return; + } + facet = facet.keyField(filterSrv.getTimeField()).valueField($scope.panel.value_field); + } + facet = facet.interval(_interval).facetFilter($scope.sjs.QueryFilter(query)); + request = request.facet(facet).size(0); + + }); + + // Populate the inspector panel + $scope.populate_modal(request); + + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + } + var time_field = filterSrv.getTimeField(); + var start_time = filterSrv.getStartTime(); + var end_time = filterSrv.getEndTime(); + + // facet.range.end does NOT accept * as a value, need to convert it to NOW + if (end_time === '*') { + end_time = 'NOW'; + } + + var wt_json = '&wt=json'; + var rows_limit = '&rows=0'; // for histogram, we do not need the actual response doc, so set rows=0 + var facet_gap = $scope.sjs.convertFacetGap($scope.panel.interval); + var facet = '&facet=true' + + '&facet.range=' + time_field + + '&facet.range.start=' + start_time + + '&facet.range.end=' + end_time + + '&facet.range.gap=' + facet_gap; + var values_mode_query = ''; + + // For mode = value + if ($scope.panel.mode === 'values' || $scope.panel.mode === 'value') { + if (!$scope.panel.value_field) { + $scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified"; + return; + } + + values_mode_query = '&fl=' + time_field + ' ' + $scope.panel.value_field; + rows_limit = '&rows=' + $scope.panel.max_rows; + facet = ''; + + // if Group By Field is specified + if ($scope.panel.group_field) { + values_mode_query += '&group=true&group.field=' + $scope.panel.group_field + '&group.limit=' + $scope.panel.max_rows; + } + } + + var mypromises = []; + var threshold_1 = '*'; + var threshold_1_1 = '*'; + var threshold_2 = '*'; + var threshold_2_1 = '*'; + var threshold_3 = '*'; + var threshold_3_1 = '*'; + var temp_q=""; + if ($scope.panel.mode === 'value' || $scope.panel.mode === 'counts') { + var arr_id = [0]; + if ($scope.panel.segment === 2) { + arr_id = [1, 0]; + threshold_1 = String($scope.panel.threshold_first - 1); + threshold_1_1 = String($scope.panel.threshold_first); + } else if ($scope.panel.segment === 3) { + arr_id = [2, 1, 0]; + threshold_1 = String($scope.panel.threshold_first - 1); + threshold_1_1 = String($scope.panel.threshold_first); + threshold_2 = String($scope.panel.threshold_second - 1); + threshold_2_1 = String($scope.panel.threshold_second); + } else if ($scope.panel.segment === 4) { + arr_id = [3, 2, 1, 0]; + threshold_1 = String($scope.panel.threshold_first - 1); + threshold_1_1 = String($scope.panel.threshold_first); + threshold_2 = String($scope.panel.threshold_second - 1); + threshold_2_1 = String($scope.panel.threshold_second); + threshold_3 = String($scope.panel.threshold_third - 1); + threshold_3_1 = String($scope.panel.threshold_third); + } + if ($scope.panel.reverse === 1) { + arr_id = arr_id.reverse(); + } + _.each(arr_id, function (id) { + if (id === 0) { + //temp_q = temp_q.replace(/responseElapsed%3A%5B0%20TO%2020000%5D/,"connectElapsed%3A%5B0%20TO%2020000%5D"); + temp_q = 'q=' + $scope.panel.value_field + '%3A%5B' + 0 + '%20TO%20' + threshold_1 + '%5D' + wt_json + rows_limit + fq + facet + values_mode_query; + } + else if (id === 1) { + //temp_q = temp_q.replace(/responseElapsed%3A%5B20000%20TO%2030000%5D/,"connectElapsed%3A%5B20000%20TO%2030000%5D"); + temp_q = 'q=' + $scope.panel.value_field + '%3A%5B' + threshold_1_1 + '%20TO%20' + threshold_2 + '%5D' + wt_json + rows_limit + fq + facet + values_mode_query; + } else if (id === 2) { + //temp_q = temp_q.replace("responseElapsed%3A%5B30000%20TO%20*%5D","connectElapsed%3A%5B30000%20TO%20*%5D"); + temp_q = 'q=' + $scope.panel.value_field + '%3A%5B' + threshold_2_1 + '%20TO%20' + threshold_3 + '%5D' + wt_json + rows_limit + fq + facet + values_mode_query; + } else { + temp_q = 'q=' + $scope.panel.value_field + '%3A%5B' + threshold_3_1 + '%20TO%20' + '*' + '%5D' + wt_json + rows_limit + fq + facet + values_mode_query; + } + + + $scope.panel.queries.query += temp_q + "\n"; + if ($scope.panel.queries.custom !== null) { + request = request.setQuery(temp_q + $scope.panel.queries.custom); + } else { + request = request.setQuery(temp_q); + } + mypromises.push(request.doSearch()); + }); + + + } else { + + _.each($scope.panel.queries.ids, function (id) { + temp_q = querySrv.getQuery(id) + wt_json + rows_limit + fq + facet + values_mode_query; + + $scope.panel.queries.query += temp_q + "\n"; + if ($scope.panel.queries.custom !== null) { + request = request.setQuery(temp_q + $scope.panel.queries.custom); + } else { + request = request.setQuery(temp_q); + } + mypromises.push(request.doSearch()); + }); + } + + if (dashboard.current.services.query.ids.length >= 1) { + $q.all(mypromises).then(function (results) { + $scope.panelMeta.loading = false; + if (segment === 0) { + $scope.hits = 0; + $scope.data = []; + query_id = $scope.query_id = new Date().getTime(); + } + // Convert facet ids to numbers + // var facetIds = _.map(_.keys(results.facets),function(k){return parseInt(k, 10);}); + //var facetIds = [0]; // Need to fix this + + // Make sure we're still on the same query/queries + // TODO: We probably DON'T NEED THIS unless we have to support multiple queries in query module. + // if ($scope.query_id === query_id && _.difference(facetIds, $scope.panel.queries.ids).length === 0) { + var i = 0, + time_series, + hits; + + _.each($scope.panel.queries.ids, function (id, index) { + // Check for error and abort if found + if (!(_.isUndefined(results[index].error))) { + $scope.panel.error = $scope.parse_error(results[index].error.msg); + return; + } + // we need to initialize the data variable on the first run, + // and when we are working on the first segment of the data. + if (_.isUndefined($scope.data[i]) || segment === 0) { + time_series = new timeSeries.ZeroFilled({ + interval: _interval, + start_date: _range && _range.from, + end_date: _range && _range.to, + fill_style: 'minimal' + }); + hits = 0; + } else { + time_series = $scope.data[i].time_series; + // Bug fix for wrong event count: + // Solr don't need to accumulate hits count since it can get total count from facet query. + // Therefore, I need to set hits and $scope.hits to zero. + // hits = $scope.data[i].hits; + hits = 0; + $scope.hits = 0; + } + + // Solr facet counts response is in one big array. + // So no need to get each segment like Elasticsearch does. + var entry_time, entries, entry_value; + if ($scope.panel.mode === 'count' || $scope.panel.mode === 'counts') { + // Entries from facet_ranges counts + entries = results[index].facet_counts.facet_ranges[time_field].counts; + for (var j = 0; j < entries.length; j++) { + entry_time = new Date(entries[j]).getTime(); // convert to millisec + j++; + var entry_count = entries[j]; + var nowTime = new Date().getTime(); + if(entry_time<=nowTime){ + time_series.addValue(entry_time, entry_count); + hits += entry_count; // The series level hits counter + $scope.hits += entry_count; + }// Entire dataset level hits counter + } + } else if ($scope.panel.mode === 'values' || $scope.panel.mode === 'value') { + if ($scope.panel.group_field) { + // Group By Field is specified + var groups = results[index].grouped[$scope.panel.group_field].groups; + + for (var j = 0; j < groups.length; j++) { // jshint ignore: line + var docs = groups[j].doclist.docs; + var group_time_series = new timeSeries.ZeroFilled({ + interval: _interval, + start_date: _range && _range.from, + end_date: _range && _range.to, + fill_style: 'minimal' + }); + hits = 0; + + // loop through each group results + for (var k = 0; k < docs.length; k++) { + entry_time = new Date(docs[k][time_field]).getTime(); // convert to millisec + entry_value = docs[k][$scope.panel.value_field]; + group_time_series.addValue(entry_time, entry_value); + hits += 1; + $scope.hits += 1; + } + + $scope.data[j] = { + // info: querySrv.list[id], + // Need to define chart info here according to the results, cannot use querySrv.list[id] + info: { + alias: groups[j].groupValue, + color: querySrv.colors[j], + + }, + time_series: group_time_series, + hits: hits + }; + } + } else { // Group By Field is not specified + entries = results[index].response.docs; + for (var j = 0; j < entries.length; j++) { // jshint ignore: line + entry_time = new Date(entries[j][time_field]).getTime(); // convert to millisec + entry_value = entries[j][$scope.panel.value_field]; + time_series.addValue(entry_time, entry_value); + hits += 1; + $scope.hits += 1; + } + + $scope.data[i] = { + info: querySrv.list[id], + time_series: time_series, + hits: hits + }; + } + } + + if ($scope.panel.mode !== 'values' || $scope.panel.mode !== 'value') { + $scope.data[i] = { + info: querySrv.list[id], + time_series: time_series, + hits: hits + }; + } + + i++; + }); + + // Tell the histogram directive to render. + $scope.$emit('render'); + // } + }); + } + } + }; + + // function $scope.zoom + // factor :: Zoom factor, so 0.5 = cuts timespan in half, 2 doubles timespan + $scope.zoom = function(factor) { + var _range = filterSrv.timeRange('min'); + var _timespan = (_range.to.valueOf() - _range.from.valueOf()); + var _center = _range.to.valueOf() - _timespan/2; + + var _to = (_center + (_timespan*factor)/2); + var _from = (_center - (_timespan*factor)/2); + + // If we're not already looking into the future, don't. + if(_to > Date.now() && _range.to < Date.now()) { + var _offset = _to - Date.now(); + _from = _from - _offset; + _to = Date.now(); + } + + var time_field = filterSrv.getTimeField(); + if(factor > 1) { + filterSrv.removeByType('time'); + } + + filterSrv.set({ + type:'time', + from:moment.utc(_from).toDate(), + to:moment.utc(_to).toDate(), + field:time_field + }); + + dashboard.refresh(); + }; + + // I really don't like this function, too much dom manip. Break out into directive? + $scope.populate_modal = function(request) { + $scope.inspector = angular.toJson(JSON.parse(request.toString()),true); + }; + + $scope.set_refresh = function (state) { + $scope.refresh = state; + }; + + $scope.close_edit = function() { + if($scope.refresh) { + $scope.get_data(); + } + $scope.refresh = false; + $scope.$emit('render'); + }; + + $scope.render = function() { + $scope.$emit('render'); + }; + + }); + + module.directive('apihistogramChart', function(dashboard, filterSrv) { + return { + restrict: 'A', + template: '
', + link: function(scope, elem) { + + // Receive render events + scope.$on('render',function(){ + render_panel(); + }); + + // Re-render if the window is resized + angular.element(window).bind('resize', function(){ + render_panel(); + }); + + // Function for rendering panel + function render_panel() { + // IE doesn't work without this + elem.css({height:scope.panel.height || scope.row.height}); + + // Populate from the query service + var num_all = 0; + + _.each(scope.data, function(seri) { + num_all += seri.hits; + }); + try { + var label_i = 0; + _.each(scope.data, function(series) { + series.color = series.info.color; + label_i ++; + //series.color = '%'; + var mid = parseFloat((100*series.hits/num_all).toFixed(2)); + series.hits = mid; + if(label_i ===2){ + series.info.alias = "Timeout% "; + }else if(label_i === 3){ + series.info.alias = "Normal% "; + }else if(label_i === 1){ + series.info.alias = "Error% ";} + series.label = series.info.alias; + + }); + } catch(e) {return;} + + // Set barwidth based on specified interval + var barwidth = kbn.interval_to_ms(scope.panel.interval); + + var stack = scope.panel.stack ? true : null; + + var xLabel = ""; + var xunit =' '; + + if(scope.panel.value_field === 'cpu'){ + xunit ='%'; + }else if(scope.panel.value_field === 'UsedMemery'){ + xunit ='MB'; + }else if(scope.panel.value_field === 'FreeDiskSpace'){ + xunit ='GB'; + } + if(scope.panel.mode === 'value'||scope.panel.mode === 'counts'){ + if (scope.panel.segment === 5){ + xLabel = "Threshold:"+' '+scope.panel.threshold_first+' and '+scope.panel.threshold_second+' and '+scope.panel.threshold_third; + }else if(scope.panel.segment === 3 ||scope.panel.segment === 4){ + xLabel = "Warning:>="+' '+scope.panel.threshold_first+xunit+' and <'+scope.panel.threshold_second+xunit+';'+'Risk:>='+scope.panel.threshold_second+xunit; + if(scope.panel.reverse){ + xLabel = "Warning:>"+' '+scope.panel.threshold_first+xunit+' and <='+scope.panel.threshold_second+xunit+';'+'Risk:<='+scope.panel.threshold_first+xunit; + } + }else if(scope.panel.segment === 2){ + xLabel = "Threshold:"+scope.panel.threshold_first; + } + } + // Populate element + try { + var options = { + legend: { show: false }, + series: { + stackpercent: scope.panel.stack ? scope.panel.percentage : false, + stack: scope.panel.percentage ? null : stack, + lines: { + show: scope.panel.lines, + // Silly, but fixes bug in stacked percentages + fill: scope.panel.fill === 0 ? 0.001 : scope.panel.fill/10, + lineWidth: scope.panel.linewidth, + steps: false + }, + bars: { + show: scope.panel.bars, + fill: 1, + barWidth: barwidth/1.8, + zero: false, + lineWidth: 0 + }, + points: { + show: scope.panel.points, + fill: 1, + fillColor: false, + radius: 5 + }, + shadowSize: 1 + }, + axisLabels: { + show: true + }, + yaxis: { + show: scope.panel['y-axis'], + min:0, + + //min: null, // TODO - make this adjusted dynamicmally, and add it to configuration panel + //max: scope.panel.percentage && scope.panel.stack ? 100 : null, + axisLabel: scope.panel.mode, + }, + xaxis: { + timezone: scope.panel.timezone, + show: 1, + mode: "time", + + //min: _.isUndefined(scope.range.from) ? null : scope.range.from.getTime(), + //max: _.isUndefined(scope.range.to) ? null : scope.range.to.getTime(), + timeformat: time_format(scope.panel.interval), + label: "Datetime", + axisLabel: scope.panel['x-axis']?xLabel:'', + }, + grid: { + backgroundColor: null, + borderWidth: 0, + hoverable: true, + color: '#c8c8c8' + } + }; + + if(scope.panel.interactive) { + options.selection = { mode: "x", color: '#666' }; + } + + // when rendering stacked bars, we need to ensure each point that has data is zero-filled + // so that the stacking happens in the proper order + var required_times = []; + if (scope.data.length > 1) { + required_times = Array.prototype.concat.apply([], _.map(scope.data, function (query) { + return query.time_series.getOrderedTimes(); + })); + required_times = _.uniq(required_times.sort(function (a, b) { + // decending numeric sort + return a-b; + }), true); + } + + for (var i = 0; i < scope.data.length; i++) { + scope.data[i].data = scope.data[i].time_series.getFlotPairs(required_times); + } + + // ISSUE: SOL-76 + // If 'lines_smooth' is enabled, loop through $scope.data[] and remove zero filled entries. + // Without zero values, the line chart will appear smooth as SiLK ;-) + if (scope.panel.lines_smooth) { + for (var i=0; i < scope.data.length; i++) { // jshint ignore: line + var new_data = []; + for (var j=0; j < scope.data[i].data.length; j++) { + // if value of the timestamp !== 0, then add it to new_data + if (scope.data[i].data[j][1] !== 0) { + new_data.push(scope.data[i].data[j]); + } + } + scope.data[i].data = new_data; + } + } + + scope.plot = $.plot(elem, scope.data, options); + } catch(e) { + // TODO: Need to fix bug => "Invalid dimensions for plot, width = 0, height = 200" + // console.log(e); + } + } + + function time_format(interval) { + var _int = kbn.interval_to_seconds(interval); + if(_int >= 2628000) { + return "%m/%y"; + } + if(_int >= 86400) { + return "%m/%d/%y"; + } + if(_int >= 60) { + return "%H:%M
%m/%d"; + } + + return "%H:%M:%S"; + } + + var $tooltip = $('
'); + /* + elem.bind("plothover", function (event, pos, item) { + var group, value; + var allSeries = scope.plot.getData(); + if (item) { + + if (item.series.info.alias.substring(0,item.series.info.alias.length-2) || scope.panel.tooltip.query_as_alias) { + group = '' + + '' + ' ' + + (item.series.info.alias.substring(0,item.series.info.alias.length-2) || item.series.info.query)+ + '
'; + } else { + group = kbn.query_color_dot(item.series.color, 15) + ' '; + } + if (scope.panel.stack && scope.panel.tooltip.value_type === 'individual') { + value = item.datapoint[1] - item.datapoint[2]; + } else { + value = item.datapoint[1]; + } + $tooltip + .html( + group + dashboard.numberWithCommas(value) + " @ " + (scope.panel.timezone === 'utc'? moment.utc(item.datapoint[0]).format('MM/DD HH:mm:ss') : moment(item.datapoint[0]).format('MM/DD HH:mm:ss')) + // group + dashboard.numberWithCommas(value) + " @ " + moment(item.datapoint[0]).format('MM/DD HH:mm:ss') + // group + dashboard.numberWithCommas(value) + " @ " + moment(item.datapoint[0]) + ) + .place_tt(pos.pageX, pos.pageY); + } else { + $tooltip.detach(); + } + }); + */ + + elem.bind("plothover", function (event, pos, item) { + var group, value; + if (item) { + if (item.series.info.alias.substring(0,item.series.info.alias.length-2) || scope.panel.tooltip.query_as_alias) { + group = '' + + '' + ' ' + + (item.series.info.alias.substring(0,item.series.info.alias.length-2) || item.series.info.query)+ + '
'; + } else { + group = kbn.query_color_dot(item.series.color, 15) + ' '; + } + if (scope.panel.stack && scope.panel.tooltip.value_type === 'individual') { + value = item.datapoint[1] - item.datapoint[2]; + } else { + value = item.datapoint[1]; + } + + var lnLastValue = value; + var isr =0; + var isnormal = 3; + + var lbPositiveValue = (lnLastValue>0); + + var lsItemTT=""; + var lsTT=""; + var isgroup = group; + var isvalue = value; + if(scope.panel.mode !== 'value' || lnLastValue !==0){ + lsItemTT = group + dashboard.numberWithCommas(value) + " @ " + (scope.panel.timezone === 'utc'? moment.utc(item.datapoint[0]).format('MM/DD HH:mm:ss') : moment(item.datapoint[0]).format('MM/DD HH:mm:ss')); + lsTT = lsItemTT; + isr =1; + }else{ + isnormal--; + } + + var hoverSeries = item.series; + var x = item.datapoint[0]; + // y = item.datapoint[1]; + + + var allSeries = scope.plot.getData(); + var posSerie = -1; + for (var i= allSeries.length - 1 ; i>=0; i--) { + + //if stack stop at the first positive value + if (scope.panel.stack && lbPositiveValue){ + break; + } + + var s = allSeries[i]; + i = parseInt(i); + + + if (s === hoverSeries ) { + posSerie = i; + } + + //not consider serie "upper" the hover serie + if ( i >= posSerie ){ + continue; + } + + //search in current serie a point with de same position. + for(var j= 0; j< s.data.length;j++){ + var p = s.data[j]; + if (p[0] === x ){ + + if (scope.panel.stack && scope.panel.tooltip.value_type === 'individual' && !isNaN(p[2])) { + value = p[1] - p[2]; + } else { + value = p[1]; + } + + lbPositiveValue = value > 0; + + if (! scope.panel.stack && value !== lnLastValue){ + break; + } + + posSerie = i; + lnLastValue = value; + + + if (s.info.alias.substring(0,s.info.alias.length-2) || scope.panel.tooltip.query_as_alias) { + group = '' + + '' + ' ' + + (s.info.alias.substring(0,s.info.alias.length-2) || s.info.query)+ + '
'; + } else { + group = kbn.query_color_dot(s.color, 15) + ' '; + } + + if(scope.panel.mode !== 'value' || lnLastValue !==0){ + + lsItemTT = group + dashboard.numberWithCommas(value) + " @ " + (scope.panel.timezone === 'utc'? moment.utc(p[0]).format('MM/DD HH:mm:ss') : moment(p[0]).format('MM/DD HH:mm:ss')); + lsTT = lsTT +"
"+ lsItemTT; + isr=1; + }else{ + isnormal--; + } + break; + } + } + } + + + if(!isnormal){ + lsItemTT = isgroup + dashboard.numberWithCommas(isvalue) + " @ " + (scope.panel.timezone === 'utc'? moment.utc(item.datapoint[0]).format('MM/DD HH:mm:ss') : moment(item.datapoint[0]).format('MM/DD HH:mm:ss')); + lsTT = lsItemTT; + isr=1; + } + if(isr){ + $tooltip + .html( lsTT ) + .place_tt(pos.pageX, pos.pageY); + } + } else { + $tooltip.detach(); + } + }); + elem.bind("plotselected", function (event, ranges) { + + filterSrv.set({ + type: 'time', + // from : moment.utc(ranges.xaxis.from), + // to : moment.utc(ranges.xaxis.to), + from: moment.utc(ranges.xaxis.from).toDate(), + to: moment.utc(ranges.xaxis.to).toDate(), + field: filterSrv.getTimeField() + }); + dashboard.current.linkage_id = scope.panel.linkage_id; + dashboard.current.enable_linkage = false; + dashboard.refresh(); + + }); + + } + }; + }); + +}); diff --git a/src/app/panels/apihistogram/timeSeries.js b/src/app/panels/apihistogram/timeSeries.js new file mode 100644 index 000000000..96054fa7d --- /dev/null +++ b/src/app/panels/apihistogram/timeSeries.js @@ -0,0 +1,179 @@ +define([ + 'underscore', + './interval' +], +function (_, Interval) { + 'use strict'; + + var ts = {}; + + // map compatable parseInt + function base10Int(val) { + return parseInt(val, 10); + } + + // trim the ms off of a time, but return it with empty ms. + function getDatesTime(date) { + return Math.floor(date.getTime() / 1000)*1000; + } + + /** + * Certain graphs require 0 entries to be specified for them to render + * properly (like the line graph). So with this we will caluclate all of + * the expected time measurements, and fill the missing ones in with 0 + * @param {object} opts An object specifying some/all of the options + * + * OPTIONS: + * @opt {string} interval The interval notion describing the expected spacing between + * each data point. + * @opt {date} start_date (optional) The start point for the time series, setting this and the + * end_date will ensure that the series streches to resemble the entire + * expected result + * @opt {date} end_date (optional) The end point for the time series, see start_date + * @opt {string} fill_style Either "minimal", or "all" describing the strategy used to zero-fill + * the series. + */ + ts.ZeroFilled = function (opts) { + opts = _.defaults(opts, { + interval: '10m', + start_date: null, + end_date: null, + fill_style: 'minimal' + }); + + // the expected differenece between readings. + this.interval = new Interval(opts.interval); + + // will keep all values here, keyed by their time + this._data = {}; + this.start_time = opts.start_date && getDatesTime(opts.start_date); + this.end_time = opts.end_date && getDatesTime(opts.end_date); + this.opts = opts; + }; + + /** + * Add a row + * @param {int} time The time for the value, in + * @param {any} value The value at this time + */ + ts.ZeroFilled.prototype.addValue = function (time, value) { + if (time instanceof Date) { + time = getDatesTime(time); + } else { + time = base10Int(time); + } + if (!isNaN(time)) { + this._data[time] = (_.isUndefined(value) ? 0 : value); + } + this._cached_times = null; + }; + + /** + * Get an array of the times that have been explicitly set in the series + * @param {array} include (optional) list of timestamps to include in the response + * @return {array} An array of integer times. + */ + ts.ZeroFilled.prototype.getOrderedTimes = function (include) { + var times = _.map(_.keys(this._data), base10Int); + if (_.isArray(include)) { + times = times.concat(include); + } + return _.uniq(times.sort(function (a, b) { + // decending numeric sort + return a - b; + }), true); + }; + + /** + * return the rows in the format: + * [ [time, value], [time, value], ... ] + * + * Heavy lifting is done by _get(Min|All)FlotPairs() + * @param {array} required_times An array of timestamps that must be in the resulting pairs + * @return {array} + */ + ts.ZeroFilled.prototype.getFlotPairs = function (required_times) { + var times = this.getOrderedTimes(required_times), + strategy, + pairs; + + if(this.opts.fill_style === 'all') { + strategy = this._getAllFlotPairs; + } else { + strategy = this._getMinFlotPairs; + } + + pairs = _.reduce( + times, // what + strategy, // how + [], // where + this // context + ); + + // if the first or last pair is inside either the start or end time, + // add those times to the series with null values so the graph will stretch to contain them. + if (this.start_time && (pairs.length === 0 || pairs[0][0] > this.start_time)) { + pairs.unshift([this.start_time, null]); + } + if (this.end_time && (pairs.length === 0 || pairs[pairs.length - 1][0] < this.end_time)) { + pairs.push([this.end_time, null]); + } + + return pairs; + }; + + /** + * ** called as a reduce stragegy in getFlotPairs() ** + * Fill zero's on either side of the current time, unless there is already a measurement there or + * we are looking at an edge. + * @return {array} An array of points to plot with flot + */ + ts.ZeroFilled.prototype._getMinFlotPairs = function (result, time, i, times) { + var next, expected_next, prev, expected_prev; + + // check for previous measurement + if (i > 0) { + prev = times[i - 1]; + expected_prev = this.interval.before(time); + if (prev < expected_prev) { + result.push([expected_prev, 0]); + } + } + + // add the current time + result.push([ time, this._data[time] || 0 ]); + + // check for next measurement + if (times.length > i) { + next = times[i + 1]; + expected_next = this.interval.after(time); + if (next > expected_next) { + result.push([expected_next, 0]); + } + } + + return result; + }; + + /** + * ** called as a reduce stragegy in getFlotPairs() ** + * Fill zero's to the right of each time, until the next measurement is reached or we are at the + * last measurement + * @return {array} An array of points to plot with flot + */ + ts.ZeroFilled.prototype._getAllFlotPairs = function (result, time, i, times) { + var next, expected_next; + + result.push([ times[i], this._data[times[i]] || 0 ]); + next = times[i + 1]; + expected_next = this.interval.after(time); + for(; times.length > i && next > expected_next; expected_next = this.interval.after(expected_next)) { + result.push([expected_next, 0]); + } + + return result; + }; + + + return ts; +}); \ No newline at end of file diff --git a/src/app/panels/apipies/editor.html b/src/app/panels/apipies/editor.html new file mode 100644 index 000000000..8fb70f337 --- /dev/null +++ b/src/app/panels/apipies/editor.html @@ -0,0 +1,121 @@ +
+
+ + +
+
+ + +
+
+ + +
+
+ + + +
+
+ + +
+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+
+
Real-time (Auto-refresh)
+
+ +
+
+ + +
+
+
+
Linkage Effective
+
+ +
+ +
diff --git a/src/app/panels/apipies/module.html b/src/app/panels/apipies/module.html new file mode 100644 index 000000000..b94bb2a8a --- /dev/null +++ b/src/app/panels/apipies/module.html @@ -0,0 +1,55 @@ +
+ + + + + +
+ + + + + + + + +
+
\ No newline at end of file diff --git a/src/app/panels/apipies/module.js b/src/app/panels/apipies/module.js new file mode 100644 index 000000000..e36a7951a --- /dev/null +++ b/src/app/panels/apipies/module.js @@ -0,0 +1,1529 @@ +/* + ## pies + + ### Parameters + * style :: A hash of css styles + * size :: top N + * arrangement :: How should I arrange the query results? 'horizontal' or 'vertical' + * chart :: Show a chart? 'none', 'bar', 'pie' + * donut :: Only applies to 'pie' charts. Punches a hole in the chart for some reason + * tilt :: Only 'pie' charts. Janky 3D effect. Looks terrible 90% of the time. + * lables :: Only 'pie' charts. Labels on the pie? +*/ +define([ + '../../../../bower_components/angular/angular', + 'app', + 'underscore', + 'jquery', + 'kbn' +], +function (angular, app, _, $, kbn) { + 'use strict'; + + var module = angular.module('kibana.panels.pies', []); + app.useModule(module); + + module.controller('apipies', function($scope, $timeout, timer, querySrv, dashboard, filterSrv) { + $scope.panelMeta = { + exportfile: true, + editorTabs : [ + {title:'Queries', src:'app/partials/querySelect.html'} + ], + status : "Stable", + description : "Displays the results of a Solr facet as a pie chart, bar chart, or a table. Newly added functionality displays min/max/mean/sum of a stats field, faceted by the Solr facet field, again as a pie chart, bar chart or a table." + }; + + // Set and populate defaults + var _d = { + queries : { + mode : 'all', + ids : [], + query : '*:*', + custom : '' + }, + mode : 'count', // mode to tell which number will be used to plot the chart. + field : '', + stats_field : '', + decimal_points : 0, // The number of digits after the decimal point + exclude : [], + missing : false, + other : false, + size : 10000, + sortBy : 'count', + order : 'descending', + fontsize : 12, + linkage_id:'a', + donut : false, + tilt : false, + display:'block', + icon:"icon-caret-down", + labels : true, + ylabels :true, + logAxis : false, + arrangement : 'vertical', + RoseType : 'area', + chart : 'pie', + exportSize : 10000, + value_sort:'rs_timestamp', + defaulttimestamp:true, + lastColor : '', + spyable : true, + show_queries:true, + error : '', + chartColors : querySrv.colors, + refresh: { + enable: false, + interval: 2 + } + }; + _.defaults($scope.panel,_d); + + $scope.init = function () { + $scope.hits = 0; + //$scope.testMultivalued(); + + // Start refresh timer if enabled + if ($scope.panel.refresh.enable) { + $scope.set_timer($scope.panel.refresh.interval); + } + + $scope.$on('refresh',function(){ + $scope.get_data(); + }); + + $scope.get_data(); + }; + + $scope.testMultivalued = function() { + if($scope.panel.field && $scope.fields.typeList[$scope.panel.field] && $scope.fields.typeList[$scope.panel.field].schema.indexOf("M") > -1) { + $scope.panel.error = "Can't proceed with Multivalued field"; + return; + } + + if($scope.panel.stats_field && $scope.fields.typeList[$scope.panel.stats_field].schema.indexOf("M") > -1) { + $scope.panel.error = "Can't proceed with Multivalued field"; + return; + } + }; + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; + /** + * + * + * @param {String} filetype -'json', 'xml', 'csv' + */ + $scope.build_query = function(filetype, isForExport) { + + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + if(!$scope.panel.defaulttimestamp){ + fq = fq.replace(filterSrv.getTimeField(),$scope.panel.value_sort); + } + } + var wt_json = '&wt=' + filetype; + var rows_limit = isForExport ? '&rows=0' : ''; // for pies, we do not need the actual response doc, so set rows=0 + var facet = ''; + + if ($scope.panel.mode === 'count') { + facet = '&facet=true&facet.field=' + $scope.panel.field + '&facet.limit=' + $scope.panel.size + '&facet.missing=true'; + } else { + // if mode != 'count' then we need to use stats query + // stats does not support something like facet.limit, so we have to sort and limit the results manually. + facet = '&stats=true&stats.facet=' + $scope.panel.field + '&stats.field=' + $scope.panel.stats_field + '&facet.missing=true'; + } + facet += '&f.' + $scope.panel.field + '.facet.sort=' + ($scope.panel.sortBy || 'count'); + + var exclude_length = $scope.panel.exclude.length; + var exclude_filter = ''; + if(exclude_length > 0){ + for (var i = 0; i < exclude_length; i++) { + if($scope.panel.exclude[i] !== "") { + exclude_filter += '&fq=-' + $scope.panel.field +":"+ $scope.panel.exclude[i]; + } + } + } + + return querySrv.getORquery() + wt_json + rows_limit + fq + exclude_filter + facet + ($scope.panel.queries.custom != null ? $scope.panel.queries.custom : ''); + }; + + $scope.exportfile = function(filetype) { + + var query = this.build_query(filetype, true); + + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + var request = $scope.sjs.Request().indices(dashboard.indices), + response; + + request.setQuery(query); + + response = request.doSearch(); + + // Populate scope when we have results + response.then(function(response) { + kbn.download_response(response, filetype, "pies"); + }); + }; + + $scope.set_timer = function(refresh_interval) { + $scope.panel.refresh.interval = refresh_interval; + if (_.isNumber($scope.panel.refresh.interval)) { + timer.cancel($scope.refresh_timer); + $scope.realtime(); + } else { + timer.cancel($scope.refresh_timer); + } + }; + + $scope.realtime = function() { + if ($scope.panel.refresh.enable) { + timer.cancel($scope.refresh_timer); + + $scope.refresh_timer = timer.register($timeout(function() { + $scope.realtime(); + $scope.get_data(); + }, $scope.panel.refresh.interval*1000)); + } else { + timer.cancel($scope.refresh_timer); + } + }; + + $scope.get_data = function() { + if(($scope.panel.linkage_id === dashboard.current.linkage_id)||dashboard.current.enable_linkage){ + // Make sure we have everything for the request to complete + if (dashboard.indices.length === 0) { + return; + } + + delete $scope.panel.error; + $scope.panelMeta.loading = true; + var request, results; + + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + request = $scope.sjs.Request().indices(dashboard.indices); + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + + // Populate the inspector panel + $scope.inspector = angular.toJson(JSON.parse(request.toString()), true); + + var query = this.build_query('json', false); + + // Set the panel's query + $scope.panel.queries.query = query; + + request.setQuery(query); + + results = request.doSearch(); + + // Populate scope when we have results + results.then(function (results) { + // Check for error and abort if found + if (!(_.isUndefined(results.error))) { + $scope.panel.error = $scope.parse_error(results.error.msg); + $scope.data = []; + $scope.label = []; + $scope.panelMeta.loading = false; + $scope.$emit('render'); + return; + } + + // Function for validating HTML color by assign it to a dummy
+ // and let the browser do the work of validation. + + + // Function for customizing chart color by using field values as colors. + + + var sum = 0; + var k = 0; + var missing = 0; + $scope.panelMeta.loading = false; + $scope.hits = results.response.numFound; + $scope.data = []; + $scope.label = []; + $scope.radardata = []; + $scope.maxdata = 0; + + + if ($scope.panel.mode === 'count') { + // In count mode, the y-axis min should be zero because count value cannot be negative. + $scope.yaxis_min = 0; + + _.each(results.facet_counts.facet_fields, function (v) { + for (var i = 0; i < v.length; i++) { + var term = v[i]; + i++; + var count = v[i]; + if ($scope.maxdata < count) { + $scope.maxdata = count; + } + sum += count; + if (term === null) { + missing = count; + } else { + // if count = 0, do not add it to the chart, just skip it + if (count === 0) { + continue; + } + term = term.replace(/[\r\n]/g, ""); + + var slice = {value: count, name: term}; + $scope.label.push(term); + $scope.data.push(slice); + $scope.radardata.push(count); + } + } + }); + } else { + // In stats mode, set y-axis min to null so jquery.flot will set the scale automatically. + $scope.yaxis_min = null; + _.each(results.stats.stats_fields[$scope.panel.stats_field].facets[$scope.panel.field], function (stats_obj, facet_field) { + var slice = {label: facet_field, data: [[k, stats_obj[$scope.panel.mode]]], actions: true}; + $scope.data.push(slice); + }); + } + // Sort the results + $scope.data = _.sortBy($scope.data, function (d) { + return $scope.panel.sortBy === 'index' ? d.name : d.value; + }); + if ($scope.panel.order === 'descending') { + $scope.data.reverse(); + $scope.label.reverse(); + $scope.radardata.reverse(); + } + + // Slice it according to panel.size, and then set the x-axis values with k. + // $scope.data = $scope.data.slice(0,$scope.panel.size); + //_.each($scope.data, function(v) { + // v.data[0][0] = k; + // k++; + // }); + + if ($scope.panel.field && $scope.fields.typeList[$scope.panel.field] && $scope.fields.typeList[$scope.panel.field].schema.indexOf("T") > -1) { + $scope.hits = sum; + } + + // $scope.data.push({label:'Missing field', + // data:[[k,results.facets.pies.missing]],meta:"missing",color:'#aaa',opacity:0}); + // TODO: Hard coded to 0 for now. Solr faceting does not provide 'missing' value. + //data:[[k,missing]],meta:"missing",color:'#aaa',opacity:0}); + // $scope.data.push({label:'Other values', + // data:[[k+1,results.facets.pies.other]],meta:"other",color:'#444'}); + // TODO: Hard coded to 0 for now. Solr faceting does not provide 'other' value. + // data:[[k+1,$scope.hits-sum]],meta:"other",color:'#444'}); + + $scope.$emit('render'); + }); + } + }; + + $scope.build_search = function(term,negate) { + + if (_.isUndefined(term.meta)) { + filterSrv.set({ + type: 'terms', field: $scope.panel.field, value: term.name, + mandate: (negate ? 'mustNot' : 'must') + }); + } else if (term.meta === 'missing') { + filterSrv.set({ + type: 'exists', field: $scope.panel.field, + mandate: (negate ? 'must' : 'mustNot') + }); + } else { + return; + } + dashboard.current.linkage_id = $scope.panel.linkage_id; + dashboard.current.enable_linkage=false; + dashboard.refresh(); + + }; + + $scope.set_refresh = function (state) { + $scope.refresh = state; + // if 'count' mode is selected, set decimal_points to zero automatically. + if ($scope.panel.mode === 'count') { + $scope.panel.decimal_points = 0; + } + }; + + $scope.close_edit = function() { + // Start refresh timer if enabled + if ($scope.panel.refresh.enable) { + $scope.set_timer($scope.panel.refresh.interval); + } + + if ($scope.refresh) { + // $scope.testMultivalued(); + $scope.get_data(); + } + $scope.refresh = false; + $scope.$emit('render'); + }; + + $scope.showMeta = function(term) { + if(_.isUndefined(term.meta)) { + return true; + } + if(term.meta === 'other' && !$scope.panel.other) { + return false; + } + if(term.meta === 'missing' && !$scope.panel.missing) { + return false; + } + return true; + }; + + }); + + module.directive('apipiesChart', function(querySrv,dashboard,filterSrv) { + return { + restrict: 'A', + link: function(scope, elem) { + + // Receive render events + scope.$on('render',function(){ + render_panel(); + }); + + // Re-render if the window is resized + angular.element(window).bind('resize', function(){ + render_panel(); + }); + + // Function for rendering panel + function render_panel() { + + var colors = []; + + // IE doesn't work without this + elem.css({height:scope.panel.height||scope.row.height}); + + // Make a clone we can operate on. + + + + if (filterSrv.idsByTypeAndField('pies',scope.panel.field).length > 0) { + colors.push(scope.panel.lastColor); + } else { + colors = scope.panel.chartColors; + } + +var option_nodata = { + series: [{ + + type: 'wordCloud', + //size: ['9%', '99%'], + sizeRange: [50, 50], + //textRotation: [0, 45, 90, -45], + rotationRange: [0, 0], + //shape: 'circle', + textPadding: 0, + autoSize: { + enable: true, + minSize: 6 + }, + textStyle: { + normal: { + color: '#1a93f9' + }, + emphasis: { + shadowBlur: 10, + shadowColor: '#333' + } + }, + data: [{ + name: "NO DATA", + value: 1 + }] + }] +}; + + + var idd = scope.$id; + var echarts = require('echarts'); + + //require(['jquery.flot.pie'], function(){ + // Populate element + try { + var labelcolor = false; + if (dashboard.current.style === 'dark'){ + labelcolor = true; + } + // Add plot to scope so we can build out own legend + if(scope.panel.chart === 'dashboard') { + + + var AP_1 = 0.0; + var AP_2 = 0.0; + var AP_n = 0.0; + for (var i = 0; i < scope.data.length; i++) { + AP_n = AP_n+scope.data[i].value; + if(parseInt(scope.data[i].name)<=scope.panel.threshold_first ){ + AP_1+=scope.data[i].value; + }else if(parseInt(scope.data[i].name)scope.panel.threshold_first){ + AP_2+=scope.data[i].value*0.5; + } + } + var APdex =100; + if(AP_n !== 0){ + APdex = parseInt(100*(AP_1+AP_2)/AP_n); + //APdex = (AP_1+AP_2)/AP_n; + } + + var myChart = echarts.init(document.getElementById(idd)); + + + var option = { + + + toolbox: { + show : false, + feature : { + mark : {show: false}, + restore : {show: false}, + saveAsImage : {show: false} + } + }, + grid: { + left: '0%', + right: '0%', + bottom: '0%', + top: 90 + }, + series : [ + { + name:'Health', + + type:'gauge', + min:scope.panel.dashboard_max, + max:scope.panel.dashboard_min, + splitNumber:scope.panel.dashboard_splitNumber, + radius: '96%', + axisLine: { // åæ ‡è½´çº¿ + lineStyle: { // 属性lineStyleæŽ§åˆ¶çº¿æ¡æ ·å¼ + color: [[0.6, colors[0]],[0.82, colors[1]],[1, colors[2]]],//'#1e90ff''#F6AB60''#EB5768' + width: 5, + shadowColor : labelcolor?'#ddfdfa':colors[7], //é»˜è®¤é€æ˜Ž + shadowBlur: 40 + } + }, + axisLabel: { // åæ ‡è½´å°æ ‡è®° + textStyle: { // 属性lineStyleæŽ§åˆ¶çº¿æ¡æ ·å¼ + fontWeight: 'bolder', + color: labelcolor?'#fff':'#696969', + shadowColor : labelcolor?'#fff':colors[7], //é»˜è®¤é€æ˜Ž + shadowBlur: 40, + fontStyle: 'italic', + fontSize:scope.panel.fontsize + } + }, + axisTick: { // åæ ‡è½´å°æ ‡è®° + length :18, // 属性length控制线长 + lineStyle: { // 属性lineStyleæŽ§åˆ¶çº¿æ¡æ ·å¼ + color: 'auto', + shadowColor : labelcolor?'#fff':colors[7], //é»˜è®¤é€æ˜Ž + shadowBlur: 40 + } + }, + splitLine: { // 分隔线 + length :28, // 属性length控制线长 + lineStyle: { // 属性lineStyle(详è§lineStyleï¼‰æŽ§åˆ¶çº¿æ¡æ ·å¼ + width:4, + color: labelcolor?'#fff':colors[8], + shadowColor : labelcolor?'#fff':colors[7], //é»˜è®¤é€æ˜Ž + shadowBlur: 40 + } + }, + pointer: { // 指针 + length:'90%', + width:3 + }, + itemStyle:{ + normal:{ + color:labelcolor?'#fff':colors[6], + shadowColor: colors[7], + shadowBlur: 30, + borderWidth:2, + borderColor: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, color: colors[4] // 0% 处的颜色 + }, { + offset: 0.7, color: colors[5] // 70% 处的颜色 + },{ + offset: 1, color: '#fff' // 100% 处的颜色 + }], false) + }, + emphasis:{ + color:labelcolor?'#fff':'#696969', + shadowColor: colors[3], + shadowBlur: 30, + borderWidth:2, + borderColor: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, color: 'red' // 0% 处的颜色 + }, { + offset: 0.7, color: '#50d1f1' // 100% 处的颜色 + },{ + offset: 1, color: '#fff' // 100% 处的颜色 + }], false) + + } + }, + title : { + textStyle: { // 其余属性默认使用全局文本样å¼ï¼Œè¯¦è§TEXTSTYLE + fontWeight: 'bolder', + fontSize: scope.panel.fontsize+18, + fontStyle: 'italic', + color: labelcolor?'#fff':'#696969', + shadowColor :labelcolor?'#fff':'#696969', //é»˜è®¤é€æ˜Ž + shadowBlur: 40 + } + }, + detail : { + formatter:'{value}%', + // x, y,å•ä½px + textStyle: { // 其余属性默认使用全局文本样å¼ï¼Œè¯¦è§TEXTSTYLE + fontWeight: 'bolder', + color: labelcolor?'#fff':'#696969', + fontSize:scope.panel.fontsize+10 + } + }, + data:[{value: APdex, name: scope.panel.title}] + } + + ] +}; + // 使用刚指定的é…ç½®é¡¹å’Œæ•°æ®æ˜¾ç¤ºå›¾è¡¨ã€‚ + myChart.setOption(option); + + } + + if(scope.panel.chart === 'pie') { + + var myChart1 = echarts.init(document.getElementById(idd)); + + + var option1 = { + title : { + show:false, + x:'center' + }, + tooltip : { + trigger: 'item', + confine:true, + formatter: "{a}
{b} : {c} ({d}%)" + }, + legend: { + show:scope.panel.eLegend, + orient: scope.panel.arrangement, + left: 'left', + top:'1%', + bottom:'1%', + + textStyle:{ + fontSize:scope.panel.fontsize, + color:'auto' + }, + + data: scope.data + }, + series : [ + { + name:scope.panel.title, + type: 'pie', + + radius : scope.panel.donut ?['60%','90%']:'90%', + label :{ + normal:{ + show:scope.panel.donut ? false:scope.panel.labels, + position:scope.panel.donut ?'center':'inside', + textStyle:{ + fontSize:scope.panel.fontsize + } + }, + emphasis: { + show: scope.panel.donut, + textStyle: { + fontSize: scope.panel.fontsize, + fontWeight: 'bold' + } + } + + }, + center: ['60%', '50%'], + data:scope.data, + itemStyle: { + normal: { + color: function(params) { + var colorList = colors; + return colorList[params.dataIndex]; + }, + shadowColor: '#fff', + barBorderRadius: 5 + + }, + emphasis: { + shadowBlur: 10, + shadowOffsetX: 0, + shadowColor: 'rgba(0, 0, 0, 0.5)' + } + } + } + ] +}; + + + if(scope.data.length === 0){ + myChart1.setOption(option_nodata);}else{ + myChart1.setOption(option1); + myChart1.on('click', function (params) { + // 点击è”动 + scope.build_search(params); + + }); + + } + + } + + + if(scope.panel.chart === 'rosepie') { + + var myChart2 = echarts.init(document.getElementById(idd)); + var option2 = { + title: { + show:false, + x: "center" + }, + tooltip: { + trigger: "item", + confine:true, + formatter: "{a}
{b} : {c} ({d}%)" + }, + legend: { + show:scope.panel.eLegend, + x: "left", + orient: scope.panel.arrangement, + textStyle:{ + fontSize:scope.panel.fontsize, + color:'auto' + }, + data: scope.label + }, + label: { + normal: { + formatter: "{b} ({d}%)", + + textStyle:{ + fontSize:scope.panel.fontsize + } + } + }, + labelLine: { + normal: { + smooth: 0.6 + } + }, + + calculable: !0, + series: [{ + name: scope.panel.title, + type: "pie", + roseType: scope.panel.RoseType, + center: ['50%', '60%'], + label: { + normal: { + show: scope.panel.labels + }, + emphasis: { + show: scope.panel.labels + } + }, + lableLine: { + normal: { + show: !0 + }, + emphasis: { + show: !0 + } + }, + data: scope.data, + itemStyle: { + normal: { + color: function(params) { + var colorList = colors; + return colorList[params.dataIndex]; + }, + shadowColor: '#fff', + barBorderRadius: 5 + + } + } + }] +}; + + if(scope.data.length === 0){ + myChart2.setOption(option_nodata);}else{ + myChart2.setOption(option2); + myChart2.on('click', function (params) { + // 点击è”动 + scope.build_search(params); + }); + } + } + + if(scope.panel.chart === 'bar') { + var myChart3 = echarts.init(document.getElementById(idd)); + var option3 = { + color: ['#3398DB'], + tooltip : { + trigger: 'axis', + confine:true, + axisPointer : { // åæ ‡è½´æŒ‡ç¤ºå™¨ï¼Œåæ ‡è½´è§¦å‘æœ‰æ•ˆ + type : 'shadow' // 默认为直线,å¯é€‰ä¸ºï¼š'line' | 'shadow' + } + }, + grid: { + left: '3%', + right: '3%', + bottom: '3%', + top: '6%', + containLabel: true + }, + xAxis : [ + { + type : 'category', + data : scope.label, + axisLine:{ + show:false + }, + axisLabel:{ + show:scope.panel.labels, + textStyle:{ + color:labelcolor ? '#fff':'#4F4F4F', + fontSize:scope.panel.fontsize, + } + }, + axisTick: { + show:false, + alignWithLabel: false + } + } + ], + yAxis : [ + { + type : 'value', + splitLine: { + show :false, + lineStyle:{ + type:'dotted', + axisTick: { + show:false + }, + color: labelcolor ? '#4F4F4F':'#F8F8FF' + } + }, + axisLabel:{ + show:scope.panel.ylabels, + textStyle:{ + color:labelcolor ? '#fff':'#4F4F4F', + fontSize:scope.panel.fontsize+2, + fontStyle: 'italic' + } + }, + nameTextStyle:{ + + color:labelcolor ? '#fff':'#4F4F4F', + + + }, + axisLine:{ + show:false + } + } + ], + series : [ + { + name:scope.panel.title, + type:'bar', + barWidth: '43%', + data:scope.data, + itemStyle: { + normal: { + color: function(params) { + var colorList = colors; + return colorList[params.dataIndex]; + }, + shadowColor: '#fff', + barBorderRadius: 5 + + } + } + } + ] +}; + //æ²¡æœ‰æ•°æ®æ˜¾ç¤ºNO DATA + + if(scope.data.length === 0){ + myChart3.setOption(option_nodata);}else{ + myChart3.setOption(option3); + myChart3.on('click', function (params) { + // 点击è”动 + scope.build_search(params); + }); + } + + } + + if(scope.panel.chart === 'horizontalBar') { + var myChart33 = echarts.init(document.getElementById(idd)); + var option33 = { + color: ['#3398DB'], + tooltip : { + trigger: 'axis', + confine:true, + axisPointer : { // åæ ‡è½´æŒ‡ç¤ºå™¨ï¼Œåæ ‡è½´è§¦å‘æœ‰æ•ˆ + type : 'shadow' // 默认为直线,å¯é€‰ä¸ºï¼š'line' | 'shadow' + } + }, + grid: { + left: '3%', + right: '3%', + bottom: '3%', + top: '6%', + containLabel: true + }, + xAxis : [ + { + type : 'value', + splitLine: { + show :false, + lineStyle:{ + type:'dotted', + axisTick: { + show:false + }, + color: labelcolor ? '#4F4F4F':'#F8F8FF' + } + }, + axisLabel:{ + show:true, + textStyle:{ + color:labelcolor ? '#fff':'#4F4F4F', + fontSize:scope.panel.fontsize+2, + fontStyle: 'italic' + } + }, + nameTextStyle:{ + + color:labelcolor ? '#fff':'#4F4F4F', + + + }, + axisLine:{ + show:true, + } + } + ], + yAxis : [ + { + show:scope.panel.ylabels, + type : 'category', + data : scope.label, + axisLine:{ + show:false + }, + axisLabel:{ + inside:!scope.panel.ylabels, + show:scope.panel.ylabels, + textStyle:{ + color:labelcolor ? '#fff':'#4F4F4F', + fontSize:scope.panel.fontsize, + } + }, + axisTick: { + show:false, + alignWithLabel: false + } + } + ], + series : [ + { + name:scope.panel.title, + type:'bar', + barWidth: '43%', + data:scope.data, + itemStyle: { + normal: { + color: function(params) { + var colorList = colors; + return colorList[params.dataIndex]; + }, + shadowColor: '#fff', + barBorderRadius: 5 + + } + }, + label: { + normal: { + show: true, + formatter:scope.panel.ylabels?'{c}':'{b}:{c}', + position: scope.panel.ylabels?'right':'insideLeft', + offset:[0,-2], + textStyle: { + fontWeight:'bold', + color: labelcolor ? '#fff':'#4F4F4F', + fontSize: scope.panel.fontsize + } + } + } + } + ] + }; + //æ²¡æœ‰æ•°æ®æ˜¾ç¤ºNO DATA + + if(scope.data.length === 0){ + myChart33.setOption(option_nodata);}else{ + myChart33.setOption(option33); + myChart33.on('click', function (params) { + // 点击è”动 + scope.build_search(params); + }); + } + + } + + if(scope.panel.chart === 'radar') { + + var radarlabel = []; + + for (var i2 = 0; i2 < scope.label.length; i2++) { + + radarlabel[i2] = {name:scope.label[i2],max:scope.maxdata}; + } + + var myChart4 = echarts.init(document.getElementById(idd)); + + var dataBJ = [scope.radardata]; + + + + var lineStyle = { + normal: { + width: 1, + opacity: 0.5 + } + }; + + var option4 = { + + title: { + left: 'center', + textStyle: { + color: '#eee' + } + }, + tooltip: { + trigger: 'axis', + position: function (point) { + // 固定在顶部 + return [point[0], '10%']; + } + }, + legend: { + bottom: 5, + itemGap: 20, + textStyle: { + color: '#fff', + fontSize: scope.panel.fontsize + }, + selectedMode: 'single' + }, + radar: { + indicator: radarlabel, + shape: 'circle', + splitNumber: 5, + name: { + textStyle: { + color: labelcolor ?'rgb(238, 197, 102)':'rgba(90, 78, 53)', + fontSize: scope.panel.fontsize + } + }, + splitLine: { + lineStyle: { + color:labelcolor ? [ + 'rgba(238, 197, 102, 0.1)', 'rgba(238, 197, 102, 0.2)', + 'rgba(238, 197, 102, 0.4)', 'rgba(238, 197, 102, 0.6)', + 'rgba(238, 197, 102, 0.8)', 'rgba(238, 197, 102, 1)' + ].reverse():[ + 'rgba(90, 78, 53, 0.1)', 'rgba(90, 78, 53, 0.2)', + 'rgba(90, 78, 53, 0.4)', 'rgba(90, 78, 53, 0.6)', + 'rgba(90, 78, 53, 0.8)', 'rgba(90, 78, 53, 1)' + ].reverse() + } + }, + splitArea: { + show: false + }, + axisLine: { + lineStyle: { + color: labelcolor ?'rgba(238, 197, 102, 0.5)':'rgba(90, 78, 53, 0.5)' + } + } + }, + series: [ + { + name: scope.panel.title, + type: 'radar', + tooltip: { + trigger: 'item' + }, + lineStyle: lineStyle, + data: dataBJ, + itemStyle: { + normal: { + color: '#F9713C' + } + }, + areaStyle: { + normal: { + opacity: 0.1 + } + } + } + ] + }; + if(scope.data.length === 0){ + myChart4.setOption(option_nodata);}else{ + myChart4.setOption(option4); + } + } + + if(scope.panel.chart === 'bars'){ + + var islength = 0; + if(scope.data.length>5){ + islength =1; + } + + var myChart5 = echarts.init(document.getElementById(idd)); + var option5 = { + tooltip: { + trigger: 'axis', + confine:true, + axisPointer: { + type: 'none' + }, + formatter: function(params) { + return params[0].name + ': ' + params[0].value; + } + }, + grid: { + left: '0%', + right: '3%', + bottom: '3%', + top: '3%', + containLabel: true + }, + xAxis: { + data: scope.label, + axisTick: { + show: false + }, + axisLine: { + show: false + }, + axisLabel: { + show:scope.panel.labels, + textStyle:{ + color:'#24b2f9', + fontSize:scope.panel.fontsize, + } + } + }, + yAxis: { + splitLine: { + show: false + }, + axisTick: { + show: false + }, + axisLine: { + show: false + }, + axisLabel: { + show: scope.panel.ylabels, + margin:52, + textStyle:{ + color:labelcolor ? '#DCDCDC':'#4F4F4F', + fontSize:scope.panel.fontsize+2, + fontStyle: 'italic' + } + } + }, + //color: ['#1a75f9', '#1a93f9', '#1ab0f9', '#1acef9', '#42d3f0', '#e59d87', '#759aa0', '#dc6b67', '#efdd79', '#8dc1aa', '#ea7d52', '#8dace7', '#a6a1e1', '#FECDA3', '#FED980'], + series: [{ + name: scope.panel.title, + type: 'pictorialBar', + barCategoryGap: islength?'-60%':'-10%', + symbolSize:['120%','100%'], + // symbol: 'path://M0,10 L10,10 L5,0 L0,10 z', + symbol: 'path://M0,10 L10,10 C5.5,10 5.5,5 5,0 C4.5,5 4.5,10 0,10 z', + itemStyle: { + normal: { + color: function(params) { + var colorList = ['#1a75f9', '#1ab0f9', '#42d3f0', '#e59d87', '#759aa0', '#dc6b67', '#efdd79', '#8dc1aa', '#ea7d52', '#8dace7', '#a6a1e1', '#FECDA3', '#FED980','#bcf924','#f9ac24','#8224f9','#24e5f9','#f96524']; + return colorList[params.dataIndex]; + }, + shadowColor: '#fff', + barBorderRadius: 5, + opacity: 0.8 + + }, + emphasis: { + opacity: 1 + } + }, + data: scope.radardata, + z: 10 + }] +}; + if(scope.data.length === 0){ + myChart5.setOption(option_nodata);}else{ + myChart5.setOption(option5); + myChart5.on('click', function (params) { + // 点击è”动 + scope.build_search(params); + }); + } + + } + + if(scope.panel.chart === 'funnel'){ + + + var myChart6 = echarts.init(document.getElementById(idd)); + var option6 = { + + tooltip: { + trigger: 'item', + confine:true, + formatter: "{a}
{b} : {c}%" + }, + + legend: { + show:scope.panel.eLegend, + x: "left", + orient: scope.panel.arrangement, + textStyle:{ + fontSize:scope.panel.fontsize, + color:'auto' + }, + data: scope.label + }, + calculable: true, + series: [ + { + name:scope.panel.title, + type:'funnel', + left: '10%', + top: 6, + //x2: 80, + bottom: 6, + width: '80%', + // height: {totalHeight} - y - y2, + min: 0, + max: scope.maxdata, + sort: scope.panel.order, + gap: 2, + label: { + normal: { + show: scope.panel.labels, + position:'inside', + formatter:'{b}' + }, + emphasis: { + show: scope.panel.labels, + position:'inside', + formatter: '{b}:{c}%', + textStyle: { + + color:'#000' + } + } + }, + labelLine: { + normal: { + show:false, + length: 10, + lineStyle: { + width: 1, + type: 'solid' + } + } + }, + itemStyle: { + normal: { + color: function(params) { + var colorList = ['#1a75f9', '#1a93f9', '#1ab0f9', '#1acef9', '#42d3f0', '#dc6b67', '#efdd79', '#8dc1aa', '#ea7d52', '#8dace7', '#a6a1e1', '#FECDA3', '#FED980','#bcf924','#f9ac24','#8224f9','#24e5f9','#f96524']; + return colorList[params.dataIndex]; + }, + opacity: 0.8 + + }, + emphasis: { + opacity: 1 + } + }, + data: scope.data + + } + ] +}; + + + + + if(scope.data.length === 0){ + myChart6.setOption(option_nodata);}else{ + myChart6.setOption(option6); + myChart6.on('click', function (params) { + // 点击è”动 + scope.build_search(params); + }); + } + } + + if(scope.panel.chart === 'ebar') { + + + var myChart7 = echarts.init(document.getElementById(idd)); + + + var option7 = { + color: ['#3398DB'], + tooltip : { + trigger: 'axis', + axisPointer : { // åæ ‡è½´æŒ‡ç¤ºå™¨ï¼Œåæ ‡è½´è§¦å‘æœ‰æ•ˆ + type : 'shadow' // 默认为直线,å¯é€‰ä¸ºï¼š'line' | 'shadow' + } + }, + grid: { + left: '8%', + right: '3%', + bottom: '3%', + top: '6%', + containLabel: true + }, + xAxis : [ + { + type : 'category', + data : scope.label, + axisLine:{ + show:false + }, + axisLabel:{ + show:false, + textStyle:{ + color:'#cde5fe', + fontSize:16, + } + }, + axisTick: { + alignWithLabel: false + } + } + ], + yAxis : [ + { + type : 'value', + splitLine: { + show :true, + lineStyle:{ + type:'dotted', + color: '#0d394a' + } + }, + axisLabel:{ + textStyle:{ + color:labelcolor?'#fff':'#696969', + fontSize:scope.panel.fontsize, + fontStyle: 'italic' + } + + }, + nameTextStyle:{ + + color:'#fff', + + + }, + axisLine:{ + show:false + } + } + ], + series : [ + { + name:'Visit Top 5', + type:'bar', + barWidth: '43%', + data:scope.data, + itemStyle: { + normal: { + color: function(params) { + var colorList = ['#1a75f9', '#1a93f9', '#1ab0f9', '#1acef9', '#42d3f0', '#e59d87', '#759aa0', '#dc6b67', '#efdd79', '#8dc1aa', '#ea7d52', '#8dace7', '#a6a1e1', '#FECDA3', '#FED980']; + return colorList[params.dataIndex]; + }, + shadowColor: '#fff', + barBorderRadius: 5 + + }, + emphasis: { + color: function(params) { + var colorList = ['#ff951f', '#ff951f', '#ff951f', '#ff951f', '#ff951f', '#e59d87', '#759aa0', '#dc6b67', '#efdd79', '#8dc1aa', '#ea7d52', '#8dace7', '#a6a1e1', '#FECDA3', '#FED980']; + return colorList[params.dataIndex]; + }, + shadowColor: '#fff', + barBorderRadius: 5 + + } + } + } + ] + }; + + + // 使用刚指定的é…ç½®é¡¹å’Œæ•°æ®æ˜¾ç¤ºå›¾è¡¨ã€‚ + if(scope.data.length === 0){ + myChart7.setOption(option_nodata);}else{ + myChart7.setOption(option7); + myChart7.on('click', function (params) { + // æŽ§åˆ¶å°æ‰“å°æ•°æ®çš„åç§° + scope.build_search(params); + }); + } + } + + if(scope.panel.chart === 'liquidfill') { + + + var myChart8 = echarts.init(document.getElementById(idd)); + var series = []; + var titles = []; + + + for (var i1 = 0; i1 < scope.radardata.length; i1++) { + + var xla = scope.label[i1].replace(" ","\n"); + var x = (i1+0.5) / scope.radardata.length * 100 + '%'; + + titles.push({ + text: xla, + textAlign: 'center', + left: x, + bottom: 10, + padding: 0, + textStyle: { + color: labelcolor?'#fff':'#696969', + fontSize: 12, + fontWeight: 'normal' + } + }); + + series.push({ + animation: true, + waveAnimation: true, + + color: ['#178ad9'], + center: [x, '50%'], + radius: '65%', + + type: 'liquidFill', + shape:'path://M229.844,151.547v-166.75c0-11.92-9.662-21.582-21.58-21.582s-21.581,9.662-21.581,21.582v166.75c-9.088,6.654-14.993,17.397-14.993,29.524c0,20.2,16.374,36.575,36.574,36.575c20.199,0,36.574-16.375,36.574-36.575C244.838,168.944,238.932,158.201,229.844,151.547z', + //shape: 'path://M479.232622,0.563387605 C479.232622,0.563387605 581.318924,34.9465747 595.916359,117.247124 C610.513793,199.547674 712.946576,234.277341 712.946576,234.277341 L282.844461,664.379456 C251.594162,695.539776 210.032528,712.700992 165.814244,712.700992 C121.595959,712.700992 80.0620523,695.5408 48.7840267,664.379456 C-15.71599,600.034368 -15.71599,495.32832 48.8117536,430.984256 L479.232622,0.563387605 Z', + outline: { + show: false + }, + amplitude: 3, + waveLength: '20%', + backgroundStyle: { + color: 'none', + borderColor: labelcolor?'#fff':'#696969', + borderWidth: 1 + }, + data: [{ + // -60 到 100 度 + name:scope.label[i1], + value: scope.radardata[i1] / scope.maxdata, + rawValue: scope.radardata[i1] + }], + itemStyle: { + normal: { + shadowBlur: 0 + } + }, + label: { + normal: { + position: 'insideBottom', + distance: 20, + formatter: function(item) { + return ' ' + item.data.rawValue ; + }, + textStyle: { + color: '#178ad9', + fontSize: 15 + } + } + } + }); + } + + + + + // 使用刚指定的é…ç½®é¡¹å’Œæ•°æ®æ˜¾ç¤ºå›¾è¡¨ã€‚ + if(scope.data.length === 0){ + myChart8.setOption(option_nodata);}else{ + myChart8.setOption({ + tooltip: { + show: true, + confine:true, + formatter: function(item) { + return item.data.name +" : " +item.data.rawValue ; + } + }, + title: titles, + series: series + }); + myChart8.on('click', function (params) { + // æŽ§åˆ¶å°æ‰“å°æ•°æ®çš„åç§° + scope.build_search(params); + }); + } + } + + // Populate legend + + + } catch(e) { + elem.text(e); + } + // }); + } + + } + }; + }); + +}); diff --git a/src/app/panels/bar/editor.html b/src/app/panels/bar/editor.html old mode 100755 new mode 100644 index f427f223d..1e31a6bee --- a/src/app/panels/bar/editor.html +++ b/src/app/panels/bar/editor.html @@ -11,4 +11,11 @@
+
+
+
Linkage Effective
+
+ +
+
\ No newline at end of file diff --git a/src/app/panels/bar/module.html b/src/app/panels/bar/module.html old mode 100755 new mode 100644 index 0e16ca006..56a3f6695 --- a/src/app/panels/bar/module.html +++ b/src/app/panels/bar/module.html @@ -50,5 +50,5 @@ left: 0; } -
+
\ No newline at end of file diff --git a/src/app/panels/bar/module.js b/src/app/panels/bar/module.js old mode 100755 new mode 100644 index feaae148f..3b366385e --- a/src/app/panels/bar/module.js +++ b/src/app/panels/bar/module.js @@ -23,12 +23,7 @@ define([ module.controller('bar', function($scope, querySrv, dashboard, filterSrv) { $scope.panelMeta = { - modals: [{ - description: "Inspect", - icon: "icon-info-sign", - partial: "app/partials/inspector.html", - show: $scope.panel.spyable - }], + editorTabs: [{ title: 'Queries', src: 'app/partials/querySelect.html' @@ -45,9 +40,12 @@ define([ custom: '' }, field: '', + display:'block', + icon:"icon-caret-down", size: 10, spyable: true, - show_queries: true, + linkage_id:'a', + show_queries: true, error: '', }; _.defaults($scope.panel, _d); @@ -60,95 +58,115 @@ define([ $scope.get_data(); }; - $scope.get_data = function() { - // Make sure we have everything for the request to complete - if (dashboard.indices.length === 0) { - return; - } - delete $scope.panel.error; - $scope.panelMeta.loading = true; - var request, results; + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + - $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; - request = $scope.sjs.Request().indices(dashboard.indices); - $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + $scope.get_data = function() { + // Make sure we have everything for the request to complete + if(($scope.panel.linkage_id === dashboard.current.linkage_id)||dashboard.current.enable_linkage){ + if (dashboard.indices.length === 0) { + return; + } + delete $scope.panel.error; + $scope.panelMeta.loading = true; + var request, results; - // Populate the inspector panel - $scope.inspector = angular.toJson(JSON.parse(request.toString()), true); + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); - // Build Solr query - var fq = ''; - if (filterSrv.getSolrFq() && filterSrv.getSolrFq() !== '') { - fq = '&' + filterSrv.getSolrFq(); - } - var wt_json = '&wt=json'; - var rows_limit = '&rows=0'; // for terms, we do not need the actual response doc, so set rows=0 - var facet = '&facet=true&facet.field=' + $scope.panel.field + '&facet.limit=' + $scope.panel.size; - - // Set the panel's query - $scope.panel.queries.query = querySrv.getORquery() + wt_json + rows_limit + fq + facet; - - // Set the additional custom query - if ($scope.panel.queries.custom != null) { - request = request.setQuery($scope.panel.queries.query + $scope.panel.queries.custom); - } else { - request = request.setQuery($scope.panel.queries.query); - } + request = $scope.sjs.Request().indices(dashboard.indices); + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); - results = request.doSearch(); + // Populate the inspector panel + $scope.inspector = angular.toJson(JSON.parse(request.toString()), true); - // Populate scope when we have results - results.then(function(results) { - // Check for error and abort if found - if (!(_.isUndefined(results.error))) { - $scope.panel.error = $scope.parse_error(results.error.msg); - return; + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq() && filterSrv.getSolrFq() !== '') { + fq = '&' + filterSrv.getSolrFq(); } + var wt_json = '&wt=json'; + var rows_limit = '&rows=0'; // for terms, we do not need the actual response doc, so set rows=0 + var facet = '&facet=true&facet.field=' + $scope.panel.field + '&facet.limit=' + $scope.panel.size; + + // Set the panel's query + $scope.panel.queries.query = querySrv.getORquery() + wt_json + rows_limit + fq + facet; + + // Set the additional custom query + if ($scope.panel.queries.custom != null) { + request = request.setQuery($scope.panel.queries.query + $scope.panel.queries.custom); + } else { + request = request.setQuery($scope.panel.queries.query); + } + + results = request.doSearch(); - var sum = 0; - var missing = 0; - $scope.panelMeta.loading = false; - $scope.hits = results.response.numFound; - $scope.data = []; - $scope.maxRatio = 0; - - $scope.yaxis_min = 0; - _.each(results.facet_counts.facet_fields, function(v) { - for (var i = 0; i < v.length; i++) { - var term = v[i]; - i++; - var count = v[i]; - sum += count; - if (term === null) { - missing = count; - } else { - // if count = 0, do not add it to the chart, just skip it - if (count === 0) { - continue; - } - var slice = { - letter: term, - frequency: count - }; - if (count / $scope.hits > $scope.maxRatio) { - $scope.maxRatio = count / $scope.hits; - } - $scope.data.push(slice); + // Populate scope when we have results + results.then(function (results) { + // Check for error and abort if found + if (!(_.isUndefined(results.error))) { + $scope.panel.error = $scope.parse_error(results.error.msg); + return; } - } + + var sum = 0; + + var missing = 0; + $scope.panelMeta.loading = false; + $scope.hits = results.response.numFound; + $scope.data = []; + $scope.maxRatio = 0; + + $scope.yaxis_min = 0; + _.each(results.facet_counts.facet_fields, function (v) { + for (var i = 0; i < v.length; i++) { + var term = v[i]; + i++; + var count = v[i]; + sum += count; + if (term === null) { + missing = count; + } else { + // if count = 0, do not add it to the chart, just skip it + if (count === 0) { + continue; + } + var slice = { + letter: term, + frequency: count + }; + if (count / $scope.hits > $scope.maxRatio){ + $scope.maxRatio = count / $scope.hits; + } + $scope.data.push(slice); + } + } + }); + $scope.$emit('render'); }); - $scope.$emit('render'); - }); + } }; $scope.build_search = function(word) { - if(word) { - filterSrv.set({type:'terms',field:$scope.panel.field,value:word,mandate:'must'}); - } else { - return; - } - dashboard.refresh(); + //增加è”动控制 + + if (word) { + filterSrv.set({type: 'terms', field: $scope.panel.field, value: word, mandate: 'must'}); + } else { + return; + } + dashboard.current.linkage_id = $scope.panel.linkage_id; + dashboard.current.enable_linkage = false; + dashboard.refresh(); + }; $scope.set_refresh = function(state) { @@ -184,6 +202,7 @@ define([ // Function for rendering panel function render_panel() { element.html(""); + var width = element.parent().width(); var height = parseInt(scope.row.height); diff --git a/src/app/panels/bettermap/editor.html b/src/app/panels/bettermap/editor.html old mode 100755 new mode 100644 index e5dbb5a57..c1d80eacf --- a/src/app/panels/bettermap/editor.html +++ b/src/app/panels/bettermap/editor.html @@ -45,24 +45,10 @@
Ending Longitude
-
-
-
-
Auto Fit Bounds
- -
-
-
-
-
Default Latitude if not exists
- -
+
Linkage Effective
+
+
-
-
-
Default Longitude if not exists
- -
-
-
+ +
\ No newline at end of file diff --git a/src/app/panels/bettermap/leaflet/images/layers-2x.png b/src/app/panels/bettermap/leaflet/images/layers-2x.png old mode 100755 new mode 100644 diff --git a/src/app/panels/bettermap/leaflet/images/layers.png b/src/app/panels/bettermap/leaflet/images/layers.png old mode 100755 new mode 100644 diff --git a/src/app/panels/bettermap/leaflet/images/marker-icon-2x.png b/src/app/panels/bettermap/leaflet/images/marker-icon-2x.png old mode 100755 new mode 100644 diff --git a/src/app/panels/bettermap/leaflet/images/marker-icon.png b/src/app/panels/bettermap/leaflet/images/marker-icon.png old mode 100755 new mode 100644 diff --git a/src/app/panels/bettermap/leaflet/images/marker-shadow.png b/src/app/panels/bettermap/leaflet/images/marker-shadow.png old mode 100755 new mode 100644 diff --git a/src/app/panels/bettermap/leaflet/leaflet-src.js b/src/app/panels/bettermap/leaflet/leaflet-src.js old mode 100755 new mode 100644 diff --git a/src/app/panels/bettermap/leaflet/leaflet.css b/src/app/panels/bettermap/leaflet/leaflet.css old mode 100755 new mode 100644 index ddb7e6b8b..d7a1cdb0c --- a/src/app/panels/bettermap/leaflet/leaflet.css +++ b/src/app/panels/bettermap/leaflet/leaflet.css @@ -1,463 +1,463 @@ -/* required styles */ - -.leaflet-map-pane, -.leaflet-tile, -.leaflet-marker-icon, -.leaflet-marker-shadow, -.leaflet-tile-pane, -.leaflet-tile-container, -.leaflet-overlay-pane, -.leaflet-shadow-pane, -.leaflet-marker-pane, -.leaflet-popup-pane, -.leaflet-overlay-pane svg, -.leaflet-zoom-box, -.leaflet-image-layer, -.leaflet-layer { - position: absolute; - left: 0; - top: 0; - } -.leaflet-container { - overflow: hidden; - -ms-touch-action: none; - } -.leaflet-tile, -.leaflet-marker-icon, -.leaflet-marker-shadow { - -webkit-user-select: none; - -moz-user-select: none; - user-select: none; - -webkit-user-drag: none; - } -.leaflet-marker-icon, -.leaflet-marker-shadow { - display: block; - } -/* map is broken in FF if you have max-width: 100% on tiles */ -.leaflet-container img { - max-width: none !important; - } -/* stupid Android 2 doesn't understand "max-width: none" properly */ -.leaflet-container img.leaflet-image-layer { - max-width: 15000px !important; - } -.leaflet-tile { - filter: inherit; - visibility: hidden; - } -.leaflet-tile-loaded { - visibility: inherit; - } -.leaflet-zoom-box { - width: 0; - height: 0; - } - -.leaflet-tile-pane { z-index: 2; } -.leaflet-objects-pane { z-index: 3; } -.leaflet-overlay-pane { z-index: 4; } -.leaflet-shadow-pane { z-index: 5; } -.leaflet-marker-pane { z-index: 6; } -.leaflet-popup-pane { z-index: 7; } - - -/* control positioning */ - -.leaflet-control { - position: relative; - z-index: 7; - pointer-events: auto; - } -.leaflet-top, -.leaflet-bottom { - position: absolute; - z-index: 1000; - pointer-events: none; - } -.leaflet-top { - top: 0; - } -.leaflet-right { - right: 0; - } -.leaflet-bottom { - bottom: 0; - } -.leaflet-left { - left: 0; - } -.leaflet-control { - float: left; - clear: both; - } -.leaflet-right .leaflet-control { - float: right; - } -.leaflet-top .leaflet-control { - margin-top: 10px; - } -.leaflet-bottom .leaflet-control { - margin-bottom: 10px; - } -.leaflet-left .leaflet-control { - margin-left: 10px; - } -.leaflet-right .leaflet-control { - margin-right: 10px; - } - - -/* zoom and fade animations */ - -.leaflet-fade-anim .leaflet-tile, -.leaflet-fade-anim .leaflet-popup { - opacity: 0; - -webkit-transition: opacity 0.2s linear; - -moz-transition: opacity 0.2s linear; - -o-transition: opacity 0.2s linear; - transition: opacity 0.2s linear; - } -.leaflet-fade-anim .leaflet-tile-loaded, -.leaflet-fade-anim .leaflet-map-pane .leaflet-popup { - opacity: 1; - } - -.leaflet-zoom-anim .leaflet-zoom-animated { - -webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1); - -moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1); - -o-transition: -o-transform 0.25s cubic-bezier(0,0,0.25,1); - transition: transform 0.25s cubic-bezier(0,0,0.25,1); - } -.leaflet-zoom-anim .leaflet-tile, -.leaflet-pan-anim .leaflet-tile, -.leaflet-touching .leaflet-zoom-animated { - -webkit-transition: none; - -moz-transition: none; - -o-transition: none; - transition: none; - } - -.leaflet-zoom-anim .leaflet-zoom-hide { - visibility: hidden; - } - - -/* cursors */ - -.leaflet-clickable { - cursor: pointer; - } -.leaflet-container { - cursor: -webkit-grab; - cursor: -moz-grab; - } -.leaflet-popup-pane, -.leaflet-control { - cursor: auto; - } -.leaflet-dragging, -.leaflet-dragging .leaflet-clickable, -.leaflet-dragging .leaflet-container { - cursor: move; - cursor: -webkit-grabbing; - cursor: -moz-grabbing; - } - - -/* visual tweaks */ - -.leaflet-container { - background: #ddd; - outline: 0; - } -.leaflet-container a { - color: #0078A8; - } -.leaflet-container a.leaflet-active { - outline: 2px solid orange; - } -.leaflet-zoom-box { - border: 2px dotted #05f; - background: white; - opacity: 0.5; - } - - -/* general typography */ -.leaflet-container { - font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif; - } - - -/* general toolbar styles */ - -.leaflet-bar { - box-shadow: 0 1px 7px rgba(0,0,0,0.65); - -webkit-border-radius: 4px; - border-radius: 4px; - } -.leaflet-bar a { - background-color: #fff; - border-bottom: 1px solid #ccc; - width: 26px; - height: 26px; - line-height: 26px; - display: block; - text-align: center; - text-decoration: none; - color: black; - } -.leaflet-bar a, -.leaflet-control-layers-toggle { - background-position: 50% 50%; - background-repeat: no-repeat; - display: block; - } -.leaflet-bar a:hover { - background-color: #f4f4f4; - } -.leaflet-bar a:first-child { - -webkit-border-top-left-radius: 4px; - border-top-left-radius: 4px; - -webkit-border-top-right-radius: 4px; - border-top-right-radius: 4px; - } -.leaflet-bar a:last-child { - -webkit-border-bottom-left-radius: 4px; - border-bottom-left-radius: 4px; - -webkit-border-bottom-right-radius: 4px; - border-bottom-right-radius: 4px; - border-bottom: none; - } -.leaflet-bar a.leaflet-disabled { - cursor: default; - background-color: #f4f4f4; - color: #bbb; - } - -.leaflet-touch .leaflet-bar { - -webkit-border-radius: 10px; - border-radius: 10px; - } -.leaflet-touch .leaflet-bar a { - width: 30px; - height: 30px; - } -.leaflet-touch .leaflet-bar a:first-child { - -webkit-border-top-left-radius: 7px; - border-top-left-radius: 7px; - -webkit-border-top-right-radius: 7px; - border-top-right-radius: 7px; - } -.leaflet-touch .leaflet-bar a:last-child { - -webkit-border-bottom-left-radius: 7px; - border-bottom-left-radius: 7px; - -webkit-border-bottom-right-radius: 7px; - border-bottom-right-radius: 7px; - border-bottom: none; - } - - -/* zoom control */ - -.leaflet-control-zoom-in { - font: bold 18px 'Lucida Console', Monaco, monospace; - } -.leaflet-control-zoom-out { - font: bold 22px 'Lucida Console', Monaco, monospace; - } - -.leaflet-touch .leaflet-control-zoom-in { - font-size: 22px; - line-height: 30px; - } -.leaflet-touch .leaflet-control-zoom-out { - font-size: 28px; - line-height: 30px; - } - - -/* layers control */ - -.leaflet-control-layers { - box-shadow: 0 1px 7px rgba(0,0,0,0.4); - background: #f8f8f9; - -webkit-border-radius: 5px; - border-radius: 5px; - } -.leaflet-control-layers-toggle { - background-image: url(images/layers.png); - width: 36px; - height: 36px; - } -.leaflet-retina .leaflet-control-layers-toggle { - background-image: url(images/layers-2x.png); - background-size: 26px 26px; - } -.leaflet-touch .leaflet-control-layers-toggle { - width: 44px; - height: 44px; - } -.leaflet-control-layers .leaflet-control-layers-list, -.leaflet-control-layers-expanded .leaflet-control-layers-toggle { - display: none; - } -.leaflet-control-layers-expanded .leaflet-control-layers-list { - display: block; - position: relative; - } -.leaflet-control-layers-expanded { - padding: 6px 10px 6px 6px; - color: #333; - background: #fff; - } -.leaflet-control-layers-selector { - margin-top: 2px; - position: relative; - top: 1px; - } -.leaflet-control-layers label { - display: block; - } -.leaflet-control-layers-separator { - height: 0; - border-top: 1px solid #ddd; - margin: 5px -10px 5px -6px; - } - - -/* attribution and scale controls */ - -.leaflet-container .leaflet-control-attribution { - background-color: rgba(255, 255, 255, 0.7); - box-shadow: 0 0 5px #bbb; - margin: 0; - } -.leaflet-control-attribution, -.leaflet-control-scale-line { - padding: 0 5px; - color: #333; - } -.leaflet-container .leaflet-control-attribution, -.leaflet-container .leaflet-control-scale { - font-size: 11px; - } -.leaflet-left .leaflet-control-scale { - margin-left: 5px; - } -.leaflet-bottom .leaflet-control-scale { - margin-bottom: 5px; - } -.leaflet-control-scale-line { - border: 2px solid #777; - border-top: none; - color: black; - line-height: 1.1; - padding: 2px 5px 1px; - font-size: 11px; - text-shadow: 1px 1px 1px #fff; - background-color: rgba(255, 255, 255, 0.5); - box-shadow: 0 -1px 5px rgba(0, 0, 0, 0.2); - white-space: nowrap; - overflow: hidden; - } -.leaflet-control-scale-line:not(:first-child) { - border-top: 2px solid #777; - border-bottom: none; - margin-top: -2px; - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); - } -.leaflet-control-scale-line:not(:first-child):not(:last-child) { - border-bottom: 2px solid #777; - } - -.leaflet-touch .leaflet-control-attribution, -.leaflet-touch .leaflet-control-layers, -.leaflet-touch .leaflet-control-zoom { - box-shadow: none; - } -.leaflet-touch .leaflet-control-layers, -.leaflet-touch .leaflet-control-zoom { - border: 4px solid rgba(0,0,0,0.3); - } - - -/* popup */ - -.leaflet-popup { - position: absolute; - text-align: center; - } -.leaflet-popup-content-wrapper { - padding: 1px; - text-align: left; - -webkit-border-radius: 12px; - border-radius: 12px; - } -.leaflet-popup-content { - margin: 13px 19px; - line-height: 1.4; - } -.leaflet-popup-content p { - margin: 18px 0; - } -.leaflet-popup-tip-container { - margin: 0 auto; - width: 40px; - height: 20px; - position: relative; - overflow: hidden; - } -.leaflet-popup-tip { - width: 17px; - height: 17px; - padding: 1px; - - margin: -10px auto 0; - - -webkit-transform: rotate(45deg); - -moz-transform: rotate(45deg); - -ms-transform: rotate(45deg); - -o-transform: rotate(45deg); - transform: rotate(45deg); - } -.leaflet-popup-content-wrapper, .leaflet-popup-tip { - background: white; - - box-shadow: 0 3px 14px rgba(0,0,0,0.4); - } -.leaflet-container a.leaflet-popup-close-button { - position: absolute; - top: 0; - right: 0; - padding: 4px 4px 0 0; - text-align: center; - width: 18px; - height: 14px; - font: 16px/14px Tahoma, Verdana, sans-serif; - color: #c3c3c3; - text-decoration: none; - font-weight: bold; - background: transparent; - } -.leaflet-container a.leaflet-popup-close-button:hover { - color: #999; - } -.leaflet-popup-scrolled { - overflow: auto; - border-bottom: 1px solid #ddd; - border-top: 1px solid #ddd; - } - - -/* div icon */ - -.leaflet-div-icon { - background: #fff; - border: 1px solid #666; - } -.leaflet-editing-icon { - -webkit-border-radius: 2px; - border-radius: 2px; - } +/* required styles */ + +.leaflet-map-pane, +.leaflet-tile, +.leaflet-marker-icon, +.leaflet-marker-shadow, +.leaflet-tile-pane, +.leaflet-tile-container, +.leaflet-overlay-pane, +.leaflet-shadow-pane, +.leaflet-marker-pane, +.leaflet-popup-pane, +.leaflet-overlay-pane svg, +.leaflet-zoom-box, +.leaflet-image-layer, +.leaflet-layer { + position: absolute; + left: 0; + top: 0; + } +.leaflet-container { + overflow: hidden; + -ms-touch-action: none; + } +.leaflet-tile, +.leaflet-marker-icon, +.leaflet-marker-shadow { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + -webkit-user-drag: none; + } +.leaflet-marker-icon, +.leaflet-marker-shadow { + display: block; + } +/* map is broken in FF if you have max-width: 100% on tiles */ +.leaflet-container img { + max-width: none !important; + } +/* stupid Android 2 doesn't understand "max-width: none" properly */ +.leaflet-container img.leaflet-image-layer { + max-width: 15000px !important; + } +.leaflet-tile { + filter: inherit; + visibility: hidden; + } +.leaflet-tile-loaded { + visibility: inherit; + } +.leaflet-zoom-box { + width: 0; + height: 0; + } + +.leaflet-tile-pane { z-index: 2; } +.leaflet-objects-pane { z-index: 3; } +.leaflet-overlay-pane { z-index: 4; } +.leaflet-shadow-pane { z-index: 5; } +.leaflet-marker-pane { z-index: 6; } +.leaflet-popup-pane { z-index: 7; } + + +/* control positioning */ + +.leaflet-control { + position: relative; + z-index: 7; + pointer-events: auto; + } +.leaflet-top, +.leaflet-bottom { + position: absolute; + z-index: 1000; + pointer-events: none; + } +.leaflet-top { + top: 0; + } +.leaflet-right { + right: 0; + } +.leaflet-bottom { + bottom: 0; + } +.leaflet-left { + left: 0; + } +.leaflet-control { + float: left; + clear: both; + } +.leaflet-right .leaflet-control { + float: right; + } +.leaflet-top .leaflet-control { + margin-top: 10px; + } +.leaflet-bottom .leaflet-control { + margin-bottom: 10px; + } +.leaflet-left .leaflet-control { + margin-left: 10px; + } +.leaflet-right .leaflet-control { + margin-right: 10px; + } + + +/* zoom and fade animations */ + +.leaflet-fade-anim .leaflet-tile, +.leaflet-fade-anim .leaflet-popup { + opacity: 0; + -webkit-transition: opacity 0.2s linear; + -moz-transition: opacity 0.2s linear; + -o-transition: opacity 0.2s linear; + transition: opacity 0.2s linear; + } +.leaflet-fade-anim .leaflet-tile-loaded, +.leaflet-fade-anim .leaflet-map-pane .leaflet-popup { + opacity: 1; + } + +.leaflet-zoom-anim .leaflet-zoom-animated { + -webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1); + -moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1); + -o-transition: -o-transform 0.25s cubic-bezier(0,0,0.25,1); + transition: transform 0.25s cubic-bezier(0,0,0.25,1); + } +.leaflet-zoom-anim .leaflet-tile, +.leaflet-pan-anim .leaflet-tile, +.leaflet-touching .leaflet-zoom-animated { + -webkit-transition: none; + -moz-transition: none; + -o-transition: none; + transition: none; + } + +.leaflet-zoom-anim .leaflet-zoom-hide { + visibility: hidden; + } + + +/* cursors */ + +.leaflet-clickable { + cursor: pointer; + } +.leaflet-container { + cursor: -webkit-grab; + cursor: -moz-grab; + } +.leaflet-popup-pane, +.leaflet-control { + cursor: auto; + } +.leaflet-dragging, +.leaflet-dragging .leaflet-clickable, +.leaflet-dragging .leaflet-container { + cursor: move; + cursor: -webkit-grabbing; + cursor: -moz-grabbing; + } + + +/* visual tweaks */ + +.leaflet-container { + background: #ddd; + outline: 0; + } +.leaflet-container a { + color: #0078A8; + } +.leaflet-container a.leaflet-active { + outline: 2px solid orange; + } +.leaflet-zoom-box { + border: 2px dotted #05f; + background: white; + opacity: 0.5; + } + + +/* general typography */ +.leaflet-container { + font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif; + } + + +/* general toolbar styles */ + +.leaflet-bar { + box-shadow: 0 1px 7px rgba(0,0,0,0.65); + -webkit-border-radius: 4px; + border-radius: 4px; + } +.leaflet-bar a { + background-color: #fff; + border-bottom: 1px solid #ccc; + width: 26px; + height: 26px; + line-height: 26px; + display: block; + text-align: center; + text-decoration: none; + color: black; + } +.leaflet-bar a, +.leaflet-control-layers-toggle { + background-position: 50% 50%; + background-repeat: no-repeat; + display: block; + } +.leaflet-bar a:hover { + background-color: #f4f4f4; + } +.leaflet-bar a:first-child { + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + } +.leaflet-bar a:last-child { + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + border-bottom: none; + } +.leaflet-bar a.leaflet-disabled { + cursor: default; + background-color: #f4f4f4; + color: #bbb; + } + +.leaflet-touch .leaflet-bar { + -webkit-border-radius: 10px; + border-radius: 10px; + } +.leaflet-touch .leaflet-bar a { + width: 30px; + height: 30px; + } +.leaflet-touch .leaflet-bar a:first-child { + -webkit-border-top-left-radius: 7px; + border-top-left-radius: 7px; + -webkit-border-top-right-radius: 7px; + border-top-right-radius: 7px; + } +.leaflet-touch .leaflet-bar a:last-child { + -webkit-border-bottom-left-radius: 7px; + border-bottom-left-radius: 7px; + -webkit-border-bottom-right-radius: 7px; + border-bottom-right-radius: 7px; + border-bottom: none; + } + + +/* zoom control */ + +.leaflet-control-zoom-in { + font: bold 18px 'Lucida Console', Monaco, monospace; + } +.leaflet-control-zoom-out { + font: bold 22px 'Lucida Console', Monaco, monospace; + } + +.leaflet-touch .leaflet-control-zoom-in { + font-size: 22px; + line-height: 30px; + } +.leaflet-touch .leaflet-control-zoom-out { + font-size: 28px; + line-height: 30px; + } + + +/* layers control */ + +.leaflet-control-layers { + box-shadow: 0 1px 7px rgba(0,0,0,0.4); + background: #f8f8f9; + -webkit-border-radius: 5px; + border-radius: 5px; + } +.leaflet-control-layers-toggle { + background-image: url(images/layers.png); + width: 36px; + height: 36px; + } +.leaflet-retina .leaflet-control-layers-toggle { + background-image: url(images/layers-2x.png); + background-size: 26px 26px; + } +.leaflet-touch .leaflet-control-layers-toggle { + width: 44px; + height: 44px; + } +.leaflet-control-layers .leaflet-control-layers-list, +.leaflet-control-layers-expanded .leaflet-control-layers-toggle { + display: none; + } +.leaflet-control-layers-expanded .leaflet-control-layers-list { + display: block; + position: relative; + } +.leaflet-control-layers-expanded { + padding: 6px 10px 6px 6px; + color: #333; + background: #fff; + } +.leaflet-control-layers-selector { + margin-top: 2px; + position: relative; + top: 1px; + } +.leaflet-control-layers label { + display: block; + } +.leaflet-control-layers-separator { + height: 0; + border-top: 1px solid #ddd; + margin: 5px -10px 5px -6px; + } + + +/* attribution and scale controls */ + +.leaflet-container .leaflet-control-attribution { + background-color: rgba(255, 255, 255, 0.7); + box-shadow: 0 0 5px #bbb; + margin: 0; + } +.leaflet-control-attribution, +.leaflet-control-scale-line { + padding: 0 5px; + color: #333; + } +.leaflet-container .leaflet-control-attribution, +.leaflet-container .leaflet-control-scale { + font-size: 11px; + } +.leaflet-left .leaflet-control-scale { + margin-left: 5px; + } +.leaflet-bottom .leaflet-control-scale { + margin-bottom: 5px; + } +.leaflet-control-scale-line { + border: 2px solid #777; + border-top: none; + color: black; + line-height: 1.1; + padding: 2px 5px 1px; + font-size: 11px; + text-shadow: 1px 1px 1px #fff; + background-color: rgba(255, 255, 255, 0.5); + box-shadow: 0 -1px 5px rgba(0, 0, 0, 0.2); + white-space: nowrap; + overflow: hidden; + } +.leaflet-control-scale-line:not(:first-child) { + border-top: 2px solid #777; + border-bottom: none; + margin-top: -2px; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); + } +.leaflet-control-scale-line:not(:first-child):not(:last-child) { + border-bottom: 2px solid #777; + } + +.leaflet-touch .leaflet-control-attribution, +.leaflet-touch .leaflet-control-layers, +.leaflet-touch .leaflet-control-zoom { + box-shadow: none; + } +.leaflet-touch .leaflet-control-layers, +.leaflet-touch .leaflet-control-zoom { + border: 4px solid rgba(0,0,0,0.3); + } + + +/* popup */ + +.leaflet-popup { + position: absolute; + text-align: center; + } +.leaflet-popup-content-wrapper { + padding: 1px; + text-align: left; + -webkit-border-radius: 12px; + border-radius: 12px; + } +.leaflet-popup-content { + margin: 13px 19px; + line-height: 1.4; + } +.leaflet-popup-content p { + margin: 18px 0; + } +.leaflet-popup-tip-container { + margin: 0 auto; + width: 40px; + height: 20px; + position: relative; + overflow: hidden; + } +.leaflet-popup-tip { + width: 17px; + height: 17px; + padding: 1px; + + margin: -10px auto 0; + + -webkit-transform: rotate(45deg); + -moz-transform: rotate(45deg); + -ms-transform: rotate(45deg); + -o-transform: rotate(45deg); + transform: rotate(45deg); + } +.leaflet-popup-content-wrapper, .leaflet-popup-tip { + background: white; + + box-shadow: 0 3px 14px rgba(0,0,0,0.4); + } +.leaflet-container a.leaflet-popup-close-button { + position: absolute; + top: 0; + right: 0; + padding: 4px 4px 0 0; + text-align: center; + width: 18px; + height: 14px; + font: 16px/14px Tahoma, Verdana, sans-serif; + color: #c3c3c3; + text-decoration: none; + font-weight: bold; + background: transparent; + } +.leaflet-container a.leaflet-popup-close-button:hover { + color: #999; + } +.leaflet-popup-scrolled { + overflow: auto; + border-bottom: 1px solid #ddd; + border-top: 1px solid #ddd; + } + + +/* div icon */ + +.leaflet-div-icon { + background: #fff; + border: 1px solid #666; + } +.leaflet-editing-icon { + -webkit-border-radius: 2px; + border-radius: 2px; + } diff --git a/src/app/panels/bettermap/leaflet/leaflet.ie.css b/src/app/panels/bettermap/leaflet/leaflet.ie.css old mode 100755 new mode 100644 index 14b84b691..f3daf1f3c --- a/src/app/panels/bettermap/leaflet/leaflet.ie.css +++ b/src/app/panels/bettermap/leaflet/leaflet.ie.css @@ -1,51 +1,51 @@ -.leaflet-vml-shape { - width: 1px; - height: 1px; - } -.lvml { - behavior: url(#default#VML); - display: inline-block; - position: absolute; - } - -.leaflet-control { - display: inline; - } - -.leaflet-popup-tip { - width: 21px; - _width: 27px; - margin: 0 auto; - _margin-top: -3px; - - filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678); - -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)"; - } -.leaflet-popup-tip-container { - margin-top: -1px; - } -.leaflet-popup-content-wrapper, .leaflet-popup-tip { - border: 1px solid #999; - } -.leaflet-popup-content-wrapper { - zoom: 1; - } - -.leaflet-control-zoom, -.leaflet-control-layers { - border: 3px solid #999; - } -.leaflet-control-layers-toggle { - } -.leaflet-control-attribution, -.leaflet-control-layers, -.leaflet-control-scale-line { - background: white; - } -.leaflet-zoom-box { - filter: alpha(opacity=50); - } -.leaflet-control-attribution { - border-top: 1px solid #bbb; - border-left: 1px solid #bbb; - } +.leaflet-vml-shape { + width: 1px; + height: 1px; + } +.lvml { + behavior: url(#default#VML); + display: inline-block; + position: absolute; + } + +.leaflet-control { + display: inline; + } + +.leaflet-popup-tip { + width: 21px; + _width: 27px; + margin: 0 auto; + _margin-top: -3px; + + filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678); + -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)"; + } +.leaflet-popup-tip-container { + margin-top: -1px; + } +.leaflet-popup-content-wrapper, .leaflet-popup-tip { + border: 1px solid #999; + } +.leaflet-popup-content-wrapper { + zoom: 1; + } + +.leaflet-control-zoom, +.leaflet-control-layers { + border: 3px solid #999; + } +.leaflet-control-layers-toggle { + } +.leaflet-control-attribution, +.leaflet-control-layers, +.leaflet-control-scale-line { + background: white; + } +.leaflet-zoom-box { + filter: alpha(opacity=50); + } +.leaflet-control-attribution { + border-top: 1px solid #bbb; + border-left: 1px solid #bbb; + } diff --git a/src/app/panels/bettermap/leaflet/leaflet.js b/src/app/panels/bettermap/leaflet/leaflet.js old mode 100755 new mode 100644 diff --git a/src/app/panels/bettermap/leaflet/plugins.css b/src/app/panels/bettermap/leaflet/plugins.css old mode 100755 new mode 100644 diff --git a/src/app/panels/bettermap/leaflet/plugins.js b/src/app/panels/bettermap/leaflet/plugins.js old mode 100755 new mode 100644 diff --git a/src/app/panels/bettermap/module.html b/src/app/panels/bettermap/module.html old mode 100755 new mode 100644 index a006d0d78..dd05b81c9 --- a/src/app/panels/bettermap/module.html +++ b/src/app/panels/bettermap/module.html @@ -1,6 +1,6 @@
-
-
+
+
\ No newline at end of file diff --git a/src/app/panels/bettermap/module.js b/src/app/panels/bettermap/module.js old mode 100755 new mode 100644 index 61a185fb2..ddd64f837 --- a/src/app/panels/bettermap/module.js +++ b/src/app/panels/bettermap/module.js @@ -24,21 +24,13 @@ function (angular, app, _, L, localRequire) { 'use strict'; var DEBUG = false; // DEBUG mode - var fitBoundsFlag = true; var module = angular.module('kibana.panels.bettermap', []); app.useModule(module); module.controller('bettermap', function($scope, querySrv, dashboard, filterSrv) { $scope.panelMeta = { - modals : [ - { - description: "Inspect", - icon: "icon-info-sign", - partial: "app/partials/inspector.html", - show: $scope.panel.spyable - } - ], + editorTabs : [ { title: 'Queries', @@ -62,13 +54,13 @@ function (angular, app, _, L, localRequire) { lat_start: '', lat_end : '', lon_start: '', - lon_end : '', + linkage_id:'a', + display:'block', + icon:"icon-caret-down", + lon_end: '', // tooltip : "_id", - field: null, - show_queries: true, - fitBoundsAuto: true, - lat_empty: 0, - lon_empty: 0 + field : null, + show_queries:true, }; _.defaults($scope.panel, _d); @@ -88,6 +80,18 @@ function (angular, app, _, L, localRequire) { $scope.refresh = state; }; + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; + $scope.close_edit = function() { if($scope.refresh) { $scope.get_data(); @@ -95,132 +99,123 @@ function (angular, app, _, L, localRequire) { $scope.refresh = false; }; - $scope.fitBounds = function() { - fitBoundsFlag = true; - $scope.$emit('draw'); - }; - $scope.get_data = function(segment,query_id) { - $scope.require(['./leaflet/plugins'], function () { - $scope.panel.error = false; - delete $scope.panel.error; - - // Make sure we have everything for the request to complete - if(dashboard.indices.length === 0) { - return; - } - - // check if [lat,lon] field is defined - if(_.isUndefined($scope.panel.field)) { - $scope.panel.error = "Please select a field that contains geo point in [lon,lat] format"; - return; - } - - // Solr.js - $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); - - var _segment = _.isUndefined(segment) ? 0 : segment; - - // var request = $scope.sjs.Request().indices(dashboard.indices); - - $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); - var boolQuery = $scope.sjs.BoolQuery(); - _.each($scope.panel.queries.ids,function(id) { - boolQuery = boolQuery.should(querySrv.getEjsObj(id)); - }); - - var request = $scope.sjs.Request().indices(dashboard.indices[_segment]); - - request = request.query( - $scope.sjs.FilteredQuery( - boolQuery, - filterSrv.getBoolFilter(filterSrv.ids) - )) - .size($scope.panel.size); // Set the size of query result + if(($scope.panel.linkage_id === dashboard.current.linkage_id)||dashboard.current.enable_linkage){ + $scope.require(['./leaflet/plugins'], function () { + $scope.panel.error = false; + delete $scope.panel.error; + + // Make sure we have everything for the request to complete + if (dashboard.indices.length === 0) { + return; + } - $scope.populate_modal(request); + // check if [lat,lon] field is defined + if (_.isUndefined($scope.panel.field)) { + $scope.panel.error = "Please select a field that contains geo point in [lon,lat] format"; + return; + } - if (DEBUG) { - console.debug('bettermap:\n\trequest=',request,'\n\trequest.toString()=',request.toString()); - } + // Solr.js + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); - // Build Solr query - var fq = ''; - if (filterSrv.getSolrFq()) { - fq = '&' + filterSrv.getSolrFq(); - } - var query_size = $scope.panel.size; - var wt_json = '&wt=json'; - var rows_limit; - var sorting = '&sort=' + filterSrv.getTimeField() + ' desc'; // Only get the latest data, sorted by time field. - - // set the size of query result - if (query_size !== undefined && query_size !== 0) { - rows_limit = '&rows=' + query_size; - } else { // default - rows_limit = '&rows=25'; - } + var _segment = _.isUndefined(segment) ? 0 : segment; - // FIXED LatLong Query - if($scope.panel.lat_start && $scope.panel.lat_end && $scope.panel.lon_start && $scope.panel.lon_end && $scope.panel.field) { - fq += '&fq=' + $scope.panel.field + ':[' + $scope.panel.lat_start + ',' + $scope.panel.lon_start + ' TO ' + $scope.panel.lat_end + ',' + $scope.panel.lon_end + ']'; - } + // var request = $scope.sjs.Request().indices(dashboard.indices); - // Set the panel's query - $scope.panel.queries.query = querySrv.getORquery() + wt_json + rows_limit + fq + sorting; + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + var boolQuery = $scope.sjs.BoolQuery(); + _.each($scope.panel.queries.ids, function (id) { + boolQuery = boolQuery.should(querySrv.getEjsObj(id)); + }); - // Set the additional custom query - if ($scope.panel.queries.custom != null) { - request = request.setQuery($scope.panel.queries.query + $scope.panel.queries.custom); - } else { - request = request.setQuery($scope.panel.queries.query); - } + var request = $scope.sjs.Request().indices(dashboard.indices[_segment]); - var results = request.doSearch(); + request = request.query( + $scope.sjs.FilteredQuery( + boolQuery, + filterSrv.getBoolFilter(filterSrv.ids) + )) + .size($scope.panel.size); // Set the size of query result - results.then(function(results) { - $scope.panelMeta.loading = false; + $scope.populate_modal(request); - if(_segment === 0) { - $scope.data = []; - query_id = $scope.query_id = new Date().getTime(); - } + if (DEBUG) { + console.debug('bettermap:\n\trequest=', request, '\n\trequest.toString()=', request.toString()); + } - // Check for error and abort if found - if(!(_.isUndefined(results.error))) { - $scope.panel.error = $scope.parse_error(results.error.msg); - return; - } + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + } + var query_size = $scope.panel.size; + var wt_json = '&wt=json'; + var rows_limit; + var sorting = '&sort=' + filterSrv.getTimeField() + ' desc'; // Only get the latest data, sorted by time field. + + // set the size of query result + if (query_size !== undefined && query_size !== 0) { + rows_limit = '&rows=' + query_size; + } else { // default + rows_limit = '&rows=25'; + } - // Check that we're still on the same query, if not stop - if($scope.query_id === query_id) { - // Keep only what we need for the set - $scope.data = $scope.data.slice(0,$scope.panel.size).concat(_.map(results.response.docs, function(hit) { - var latlon; - if (hit[$scope.panel.field]) { - latlon = hit[$scope.panel.field].split(','); - } else { - latlon = [$scope.panel.lat_empty, $scope.panel.lon_empty]; - } + // FIXED LatLong Query + if ($scope.panel.lat_start && $scope.panel.lat_end && $scope.panel.lon_start && $scope.panel.lon_end && $scope.panel.field) { + fq += '&fq=' + $scope.panel.field + ':[' + $scope.panel.lat_start + ',' + $scope.panel.lon_start + ' TO ' + $scope.panel.lat_end + ',' + $scope.panel.lon_end + ']'; + } - return { - coordinates : new L.LatLng(latlon[0],latlon[1]), - tooltip : hit[$scope.panel.tooltip] - }; - })); + // Set the panel's query + $scope.panel.queries.query = querySrv.getORquery() + wt_json + rows_limit + fq + sorting; - } else { - return; - } + // Set the additional custom query + if ($scope.panel.queries.custom != null) { + request = request.setQuery($scope.panel.queries.query + $scope.panel.queries.custom); + } else { + request = request.setQuery($scope.panel.queries.query); + } - $scope.$emit('draw'); - // Get $size results then stop querying - // Searching Solr using Segments - if($scope.data.length < $scope.panel.size && _segment+1 < dashboard.indices.length) { - $scope.get_data(_segment+1, $scope.query_id); - } + var results = request.doSearch(); + + results.then(function (results) { + $scope.panelMeta.loading = false; + + if (_segment === 0) { + $scope.data = []; + query_id = $scope.query_id = new Date().getTime(); + } + + // Check for error and abort if found + if (!(_.isUndefined(results.error))) { + $scope.panel.error = $scope.parse_error(results.error.msg); + return; + } + + // Check that we're still on the same query, if not stop + if ($scope.query_id === query_id) { + // Keep only what we need for the set + $scope.data = $scope.data.slice(0, $scope.panel.size).concat(_.map(results.response.docs, function (hit) { + var latlon = hit[$scope.panel.field].split(','); + return { + coordinates: new L.LatLng(latlon[0], latlon[1]), + tooltip: hit[$scope.panel.tooltip] + }; + })); + + } else { + return; + } + + $scope.$emit('draw'); + // Get $size results then stop querying + // Searching Solr using Segments + if ($scope.data.length < $scope.panel.size && _segment + 1 < dashboard.indices.length) { + $scope.get_data(_segment + 1, $scope.query_id); + } + }); }); - }); + } }; $scope.populate_modal = function(request) { @@ -286,10 +281,7 @@ function (angular, app, _, L, localRequire) { layerGroup.addTo(map); - if (scope.panel.fitBoundsAuto || fitBoundsFlag) { - map.fitBounds(_.pluck(scope.data,'coordinates')); - fitBoundsFlag = false; - } + map.fitBounds(_.pluck(scope.data,'coordinates')); }); } } diff --git a/src/app/panels/bmwdashboard/editor.html b/src/app/panels/bmwdashboard/editor.html new file mode 100644 index 000000000..2e4ea438b --- /dev/null +++ b/src/app/panels/bmwdashboard/editor.html @@ -0,0 +1,171 @@ +
+
+ + + + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ In {{panel.mode}} mode the configured field must be a numeric type. +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+ + +
+ +
+ + +
+
+ +
+
+ + +
+ +
+ +
Chart Settings
+
+
+
+
+
+
+ + +
+
+
+
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ + +
+
+ +
Tooltip Settings
+
+
+ + +
+
+ + +
+
+
+
Linkage Effective
+
+ +
+ +
diff --git a/src/app/panels/bmwdashboard/interval.js b/src/app/panels/bmwdashboard/interval.js new file mode 100644 index 000000000..673371fcf --- /dev/null +++ b/src/app/panels/bmwdashboard/interval.js @@ -0,0 +1,57 @@ +define([ + 'kbn' +], +function (kbn) { + 'use strict'; + + /** + * manages the interval logic + * @param {[type]} interval_string An interval string in the format '1m', '1y', etc + */ + function Interval(interval_string) { + this.string = interval_string; + + var info = kbn.describe_interval(interval_string); + this.type = info.type; + this.ms = info.sec * 1000 * info.count; + + // does the length of the interval change based on the current time? + if (this.type === 'y' || this.type === 'M') { + // we will just modify this time object rather that create a new one constantly + this.get = this.get_complex; + this.date = new Date(0); + } else { + this.get = this.get_simple; + } + } + + Interval.prototype = { + toString: function () { + return this.string; + }, + after: function(current_ms) { + return this.get(current_ms, 1); + }, + before: function (current_ms) { + return this.get(current_ms, -1); + }, + get_complex: function (current, delta) { + this.date.setTime(current); + switch(this.type) { + case 'M': + this.date.setUTCMonth(this.date.getUTCMonth() + delta); + break; + case 'y': + this.date.setUTCFullYear(this.date.getUTCFullYear() + delta); + break; + } + return this.date.getTime(); + }, + get_simple: function (current, delta) { + return current + (delta * this.ms); + } + }; + + return Interval; + +}); \ No newline at end of file diff --git a/src/app/panels/bmwdashboard/module.html b/src/app/panels/bmwdashboard/module.html new file mode 100644 index 000000000..94ca0d827 --- /dev/null +++ b/src/app/panels/bmwdashboard/module.html @@ -0,0 +1,116 @@ +
+ + +
+ +
+ + + + + + +
{{term.label}}{{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}
+ + +
+ {{term.label}} ({{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}) +

+ +
+
{{data.length - 2}}
+ +
+ +
+ + + + + + +
{{term.label}}{{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}
+
+ +
+ +
+ + + + + + +
{{term.label}}{{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}
+ + +
+ {{term.label}} ({{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}) +

+ +
+ + + + + + + + + + + + + + + + +
Term{{panel.mode | capitalize}}Action
{{term.label}}{{term.data[0][1].toFixed(panel.decimal_points)}} + + + + +
+ + +
+
+
diff --git a/src/app/panels/bmwdashboard/module.js b/src/app/panels/bmwdashboard/module.js new file mode 100644 index 000000000..c979db52c --- /dev/null +++ b/src/app/panels/bmwdashboard/module.js @@ -0,0 +1,829 @@ +/* + + ## Histogram + + ### Parameters + * auto_int :: Auto calculate data point interval? + * resolution :: If auto_int is enables, shoot for this many data points, rounding to + sane intervals + * interval :: Datapoint interval in elasticsearch date math format (eg 1d, 1w, 1y, 5y) + * fill :: Only applies to line charts. Level of area shading from 0-10 + * linewidth :: Only applies to line charts. How thick the line should be in pixels + While the editor only exposes 0-10, this can be any numeric value. + Set to 0 and you'll get something like a scatter plot + * timezone :: This isn't totally functional yet. Currently only supports browser and utc. + browser will adjust the x-axis labels to match the timezone of the user's + browser + * spyable :: Dislay the 'eye' icon that show the last elasticsearch query + * zoomlinks :: Show the zoom links? + * bars :: Show bars in the chart + * stack :: Stack multiple queries. This generally a crappy way to represent things. + You probably should just use a line chart without stacking + * points :: Should circles at the data points on the chart + * lines :: Line chart? Sweet. + * legend :: Show the legend? + * x-axis :: Show x-axis labels and grid lines + * y-axis :: Show y-axis labels and grid lines + * interactive :: Allow drag to select time range + +*/ +define([ + 'angular', + 'app', + 'jquery', + 'underscore', + 'kbn', + 'moment', + './timeSeries', + + 'jquery.flot', + 'jquery.flot.pie', + 'jquery.flot.selection', + 'jquery.flot.time', + 'jquery.flot.stack', + 'jquery.flot.stackpercent', + 'jquery.flot.axislabels' +], +function (angular, app, $, _, kbn, moment, timeSeries) { + 'use strict'; + + var module = angular.module('kibana.panels.bmwdashboard', []); + app.useModule(module); + + module.controller('bmwdashboard', function($scope, $q, querySrv, dashboard, filterSrv) { + $scope.panelMeta = { + + editorTabs : [ + { + title:'Queries', + src:'app/partials/querySelect.html' + } + ], + status : "Stable", + description : "A bucketed time series chart of the current query, including all applied time and non-time filters, when used in count mode. Uses Solr’s facet.range query parameters. In values mode, it plots the value of a specific field over time, and allows the user to group field values by a second field." + }; + + // Set and populate defaults + var _d = { + mode : 'value', + queries : { + mode : 'all', + ids : [], + query : '*:*', + custom : '' + }, + max_rows : 100000, // maximum number of rows returned from Solr (also use this for group.limit to simplify UI setting) + reverse :0, + segment :4, + threshold_first:1000, + threshold_second:2000, + cpu_first:50, + cpu_second:70, + memory_first:1500, + memory_second:1800, + value_field : null, + group_field : null, + auto_int : true, + linkage_id:'a', + total_first :'%', + fontsize:20, + field_color:'#209bf8', + resolution : 100, + interval : '5m', + intervals : ['auto','1s','1m','5m','10m','30m','1h','3h','12h','1d','1w','1M','1y'], + fill : 0, + linewidth : 3, + timezone : 'browser', // browser, utc or a standard timezone + spyable : true, + zoomlinks : true, + bars : true, + display:'block', + icon:"icon-caret-down", + stack : true, + points : false, + lines : false, + lines_smooth: false, // Enable 'smooth line' mode by removing zero values from the plot. + legend : true, + 'x-axis' : true, + 'y-axis' : true, + percentage : false, + interactive : true, + options : true, + show_queries:true, + tooltip : { + value_type: 'cumulative', + query_as_alias: false + } + }; + + _.defaults($scope.panel,_d); + + $scope.init = function() { + // Hide view options by default + $scope.options = false; + $scope.$on('refresh',function(){ + $scope.get_data(); + }); + + $scope.get_data(); + + }; + + $scope.set_interval = function(interval) { + if(interval !== 'auto') { + $scope.panel.auto_int = false; + $scope.panel.interval = interval; + } else { + $scope.panel.auto_int = true; + } + }; + + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; + + $scope.interval_label = function(interval) { + return $scope.panel.auto_int && interval === $scope.panel.interval ? interval+" (auto)" : interval; + }; + + /** + * The time range effecting the panel + * @return {[type]} [description] + */ + $scope.get_time_range = function () { + var range = $scope.range = filterSrv.timeRange('min'); + return range; + }; + + $scope.get_interval = function () { + var interval = $scope.panel.interval, + range; + if ($scope.panel.auto_int) { + range = $scope.get_time_range(); + if (range) { + interval = kbn.secondsToHms( + kbn.calculate_interval(range.from, range.to, $scope.panel.resolution, 0) / 1000 + ); + } + } + $scope.panel.interval = interval || '10m'; + return $scope.panel.interval; + }; + + /** + * Fetch the data for a chunk of a queries results. Multiple segments occur when several indicies + * need to be consulted (like timestamped logstash indicies) + * + * The results of this function are stored on the scope's data property. This property will be an + * array of objects with the properties info, time_series, and hits. These objects are used in the + * render_panel function to create the historgram. + * + * !!! Solr does not need to fetch the data in chunk because it uses a facet search and retrieve + * !!! all events from a single query. + * + * @param {number} segment The segment count, (0 based) + * @param {number} query_id The id of the query, generated on the first run and passed back when + * this call is made recursively for more segments + */ + $scope.get_data = function(segment, query_id) { + if(($scope.panel.linkage_id === dashboard.current.linkage_id)||dashboard.current.enable_linkage){ + if (_.isUndefined(segment)) { + segment = 0; + } + delete $scope.panel.error; + + // Make sure we have everything for the request to complete + if (dashboard.indices.length === 0) { + return; + } + var _range = $scope.get_time_range(); + var _interval = $scope.get_interval(_range); + + if ($scope.panel.auto_int) { + $scope.panel.interval = kbn.secondsToHms( + kbn.calculate_interval(_range.from, _range.to, $scope.panel.resolution, 0) / 1000); + } + + $scope.panelMeta.loading = true; + + // Solr + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + var request = $scope.sjs.Request().indices(dashboard.indices[segment]); + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + + + $scope.panel.queries.query = ""; + // Build the query + _.each($scope.panel.queries.ids, function (id) { + var query = $scope.sjs.FilteredQuery( + querySrv.getEjsObj(id), + filterSrv.getBoolFilter(filterSrv.ids) + ); + + var facet = $scope.sjs.DateHistogramFacet(id); + if ($scope.panel.mode === 'count' || $scope.panel.mode === 'counts') { + facet = facet.field(filterSrv.getTimeField()); + } else { + if (_.isNull($scope.panel.value_field)) { + $scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified"; + return; + } + facet = facet.keyField(filterSrv.getTimeField()).valueField($scope.panel.value_field); + } + facet = facet.interval(_interval).facetFilter($scope.sjs.QueryFilter(query)); + request = request.facet(facet).size(0); + + }); + + // Populate the inspector panel + $scope.populate_modal(request); + + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + } + var time_field = filterSrv.getTimeField(); + var start_time = filterSrv.getStartTime(); + var end_time = filterSrv.getEndTime(); + + // facet.range.end does NOT accept * as a value, need to convert it to NOW + if (end_time === '*') { + end_time = 'NOW'; + } + + var wt_json = '&wt=json'; + var rows_limit = '&rows=0'; // for histogram, we do not need the actual response doc, so set rows=0 + var facet_gap = $scope.sjs.convertFacetGap($scope.panel.interval); + var facet = '&facet=true' + + '&facet.range=' + time_field + + '&facet.range.start=' + start_time + + '&facet.range.end=' + end_time + + '&facet.range.gap=' + facet_gap; + var values_mode_query = ''; + + // For mode = value + if ($scope.panel.mode === 'values' || $scope.panel.mode === 'value') { + if (!$scope.panel.value_field) { + $scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified"; + return; + } + + values_mode_query = '&fl=' + time_field + ' ' + $scope.panel.value_field; + + rows_limit = '&rows=' + $scope.panel.max_rows; + facet = ''; + + // if Group By Field is specified + if ($scope.panel.group_field) { + values_mode_query += '&group=true&group.field=' + $scope.panel.group_field + '&group.limit=' + $scope.panel.max_rows; + } + } + + var mypromises = []; + var threshold_1 = '*'; + var threshold_2 = '*'; + + var temp_q = ""; + if ($scope.panel.mode === 'value' || $scope.panel.mode === 'counts') { + var arr_id = [0]; + if ($scope.panel.segment === 4) { + arr_id = [0, 1, 2, 3]; + + threshold_1 = String($scope.panel.threshold_first); + threshold_2 = String($scope.panel.threshold_second); + // = String($scope.panel.threshold_third); + } + + _.each(arr_id, function (id) { + if (id === 0) { + //temp_q = temp_q.replace(/responseElapsed%3A%5B0%20TO%2020000%5D/,"connectElapsed%3A%5B0%20TO%2020000%5D"); + temp_q = 'q=' + $scope.panel.value_field + '%3A%5B' + '*' + '%20TO%20' + '*' + '%5D' + wt_json + rows_limit + fq + facet + values_mode_query; + } + else if (id === 1) { + //temp_q = temp_q.replace(/responseElapsed%3A%5B20000%20TO%2030000%5D/,"connectElapsed%3A%5B20000%20TO%2030000%5D"); + temp_q = 'q=' + $scope.panel.value_field1 + '%3A%5B' + '*' + '%20TO%20' + '*' + '%5D' + wt_json + rows_limit + fq + facet + '&fl=' + time_field + ' ' + $scope.panel.value_field1; + } else if (id === 2) { + //temp_q = temp_q.replace("responseElapsed%3A%5B30000%20TO%20*%5D","connectElapsed%3A%5B30000%20TO%20*%5D"); + temp_q = 'q=' + $scope.panel.value_field2 + '%3A%5B' + '*' + '%20TO%20' + '*' + '%5D' + wt_json + rows_limit + fq + facet + '&fl=' + time_field + ' ' + $scope.panel.value_field2; + } else if (id === 3) { + //var temp_q = 'q='+$scope.panel.value_field + '%3A%5B' +threshold_3+'%20TO%20'+'*'+'%5D'+wt_json + rows_limit + fq + facet + values_mode_query; + temp_q = 'q=' + $scope.panel.value_field3 + '%3A%5B' + '*' + '%20TO%20' + '*' + '%5D' + wt_json + rows_limit + fq + facet + '&fl=' + time_field + ' ' + $scope.panel.value_field3; + + } + + + $scope.panel.queries.query += temp_q + "\n"; + if ($scope.panel.queries.custom !== null) { + request = request.setQuery(temp_q + $scope.panel.queries.custom); + } else { + request = request.setQuery(temp_q); + } + mypromises.push(request.doSearch()); + }); + + + } else { + + _.each($scope.panel.queries.ids, function (id) { + temp_q = querySrv.getQuery(id) + wt_json + rows_limit + fq + facet + values_mode_query; + + $scope.panel.queries.query += temp_q + "\n"; + if ($scope.panel.queries.custom !== null) { + request = request.setQuery(temp_q + $scope.panel.queries.custom); + } else { + request = request.setQuery(temp_q); + } + mypromises.push(request.doSearch()); + }); + } + $scope.data = []; + + if (dashboard.current.services.query.ids.length >= 1) { + $q.all(mypromises).then(function (results) { + $scope.panelMeta.loading = false; + if (segment === 0) { + $scope.hits = 0; + $scope.data = []; + query_id = $scope.query_id = new Date().getTime(); + } + // Convert facet ids to numbers + // var facetIds = _.map(_.keys(results.facets),function(k){return parseInt(k, 10);}); + //var facetIds = [0]; // Need to fix this + + // Make sure we're still on the same query/queries + // TODO: We probably DON'T NEED THIS unless we have to support multiple queries in query module. + // if ($scope.query_id === query_id && _.difference(facetIds, $scope.panel.queries.ids).length === 0) { + var i = 0, + time_series, + hits; + + _.each($scope.panel.queries.ids, function (id, index) { + // Check for error and abort if found + if (!(_.isUndefined(results[index].error))) { + $scope.panel.error = $scope.parse_error(results[index].error.msg); + return; + } + // we need to initialize the data variable on the first run, + // and when we are working on the first segment of the data. + if (_.isUndefined($scope.data[i]) || segment === 0) { + time_series = new timeSeries.ZeroFilled({ + interval: _interval, + start_date: _range && _range.from, + end_date: _range && _range.to, + fill_style: 'minimal' + }); + hits = 0; + } else { + time_series = $scope.data[i].time_series; + // Bug fix for wrong event count: + // Solr don't need to accumulate hits count since it can get total count from facet query. + // Therefore, I need to set hits and $scope.hits to zero. + // hits = $scope.data[i].hits; + hits = 0; + $scope.hits = 0; + } + + // Solr facet counts response is in one big array. + // So no need to get each segment like Elasticsearch does. + + + + $scope.data[i] = results[index].response.docs; + $scope.data[3] = results[3].response.docs; + + + i++; + }); + + // Tell the histogram directive to render. + $scope.$emit('render'); + // } + }); + } + + } + }; + + // function $scope.zoom + // factor :: Zoom factor, so 0.5 = cuts timespan in half, 2 doubles timespan + $scope.zoom = function(factor) { + var _range = filterSrv.timeRange('min'); + var _timespan = (_range.to.valueOf() - _range.from.valueOf()); + var _center = _range.to.valueOf() - _timespan/2; + + var _to = (_center + (_timespan*factor)/2); + var _from = (_center - (_timespan*factor)/2); + + // If we're not already looking into the future, don't. + if(_to > Date.now() && _range.to < Date.now()) { + var _offset = _to - Date.now(); + _from = _from - _offset; + _to = Date.now(); + } + + var time_field = filterSrv.getTimeField(); + if(factor > 1) { + filterSrv.removeByType('time'); + } + + filterSrv.set({ + type:'time', + from:moment.utc(_from).toDate(), + to:moment.utc(_to).toDate(), + field:time_field + }); + + dashboard.refresh(); + }; + + // I really don't like this function, too much dom manip. Break out into directive? + $scope.populate_modal = function(request) { + $scope.inspector = angular.toJson(JSON.parse(request.toString()),true); + }; + + $scope.set_refresh = function (state) { + $scope.refresh = state; + }; + + $scope.close_edit = function() { + if($scope.refresh) { + $scope.get_data(); + } + $scope.refresh = false; + $scope.$emit('render'); + }; + + $scope.render = function() { + $scope.$emit('render'); + }; + + }); + + module.directive('bmwdashboardChart', function(querySrv,dashboard,filterSrv) { + return { + restrict: 'A', + link: function(scope, elem) { + + // Receive render events + scope.$on('render',function(){ + render_panel(); + }); + + // Re-render if the window is resized + angular.element(window).bind('resize', function(){ + render_panel(); + }); + + // Function for rendering panel + function render_panel() { + var chartData; + var colors = []; + + // IE doesn't work without this + elem.css({height:scope.panel.height||scope.row.height}); + + // Make a clone we can operate on. + + chartData = _.clone(scope.data); + chartData = scope.panel.missing ? chartData : + _.without(chartData,_.findWhere(chartData,{meta:'missing'})); + chartData = scope.panel.other ? chartData : + _.without(chartData,_.findWhere(chartData,{meta:'other'})); + + if (filterSrv.idsByTypeAndField('terms',scope.panel.field).length > 0) { + colors.push(scope.panel.lastColor); + } else { + colors = scope.panel.chartColors; + } + + var AP_1 = 0.0; + var AP_2 = 0.0; + var AP_n = 0.0; + AP_n = AP_n+chartData[0].length; + for (var i = 0; i < chartData[0].length; i++) { + if(parseInt(chartData[0][i].responseElapsed)<=scope.panel.threshold_first ){ + AP_1+=1; + }else if(parseInt(chartData[0][i].responseElapsed)scope.panel.threshold_first){ + AP_2+=1*0.5; + } + } + var APdex_1 =100; + if(AP_n !== 0){ + APdex_1 = parseInt(100*(AP_1+AP_2)/AP_n); + + } + + var AP_1_conn = 0.0; + var AP_2_conn = 0.0; + var AP_n_conn = 0.0; + AP_n_conn = AP_n_conn+chartData[1].length; + for (var i1 = 0; i1 < chartData[1].length; i1++) { + if(parseInt(chartData[1][i1].connectElapsed)<=scope.panel.threshold_first ){ + AP_1_conn+=1; + }else if(parseInt(chartData[1][i1].connectElapsed)scope.panel.threshold_first){ + AP_2_conn+=1*0.5; + } + } + var APdex_conn =100; + if(AP_n_conn!==0){ + APdex_conn = parseInt(100*(AP_1_conn+AP_2_conn)/AP_n_conn); + + } + + var AP_1_cpu = 0.0; + var AP_2_cpu = 0.0; + var AP_n_cpu = 0.0; + AP_n_cpu = AP_n_cpu+chartData[2].length; + for (var i2 = 0; i2 < chartData[2].length; i2++) { + if(parseInt(chartData[2][i2].cpu)<=scope.panel.cpu_first){ + AP_1_cpu+=1; + }else if(parseInt(chartData[2][i2].cpu)scope.panel.cpu_first){ + AP_2_cpu+=1*0.5; + } + } + var APdex_cpu =100; + if(AP_n_cpu!==0){ + APdex_cpu = parseInt(100*(AP_1_cpu+AP_2_cpu)/AP_n_cpu); + + } + + var AP_1_me = 0.0; + var AP_2_me = 0.0; + var AP_n_me = 0.0; + AP_n_me = AP_n_me+chartData[3].length; + for (var i3 = 0; i3 < chartData[3].length; i3++) { + if(parseInt(chartData[3][i3].UsedMemery)<=scope.panel.memory_first ){ + AP_1_me+=1; + }else if(parseInt(chartData[3][i3].UsedMemery)scope.panel.memory_first){ + AP_2_me+=1*0.5; + } + } + var APdex_me =100; + if(AP_n_me!==0){ + APdex_me = parseInt(100*(AP_1_me+AP_2_me)/AP_n_me); + + } + var APdex = 100; + if(APdex>APdex_1){ + APdex = APdex_1; + } + if (APdex>APdex_conn){ + APdex=APdex_conn; + } + if (APdex>APdex_cpu){ + APdex=APdex_cpu; + } + if (APdex>APdex_me){ + APdex=APdex_me; + } + //APdex = parseInt(0.1*APdex_1+0.1*APdex_conn+0.4*APdex_cpu+0.4*APdex_me); + //APdex = parseInt(0.5*APdex_cpu+0.5*APdex_me); + + + var idd = scope.$id; + var echarts = require('echarts'); + + // Populate element + try { + // Add plot to scope so we can build out own legend + if(scope.panel.chart === 'dashboard') { + + + /* var g1 = new JustGage({ + id: idd, + value: health, + min: 0, + max: 500, + symbol: '%', + pointer: true, + pointerOptions: { + toplength: -15, + bottomlength: 10, + bottomwidth: 12, + color: '#8e8e93', + stroke: '#ffffff', + stroke_width: 3, + stroke_linecap: 'round' + }, + gaugeWidthScale: 0.6, + counter: true + + }); + */ + + var myChart = echarts.init(document.getElementById(idd)); + + // 指定图表的é…ç½®é¡¹å’Œæ•°æ® + /* var option = { + tooltip : { + formatter: "{a}
{b} : {c}%" + }, + + series: [ + { + name: 'Health', + type: 'gauge', + radius:'100%', + startAngle:225, + endAngle:-45, + axisLine: { + lineStyle: { + color:[[0.6, '#28B294'], [0.8, '#F6AB60'], [1, '#EB5768']] + } + + }, + title:{ + + textStyle:{ + color:'#d9d9d9', + fontWeight:'bold', + fontFamily:'Microsoft YaHei' + } + }, + detail: {formatter:'{value}%'}, + data: [{value:health , name: 'Health State'}] + } + ] +}; +*/ +var option = { + + + toolbox: { + show : false, + feature : { + mark : {show: false}, + restore : {show: false}, + saveAsImage : {show: false} + } + }, + grid: { + left: '0%', + right: '0%', + bottom: '0%', + top: 90 + }, + series : [ + { + name:'Health', + + type:'gauge', + min:100, + max:0, + splitNumber:10, + radius: '96%', + axisLine: { // åæ ‡è½´çº¿ + lineStyle: { // 属性lineStyleæŽ§åˆ¶çº¿æ¡æ ·å¼ + color: [[0.5, '#1e90ff'],[0.8, '#F6AB60'],[1, '#EB5768']], + width: 5, + shadowColor : '#ddfdfa', //é»˜è®¤é€æ˜Ž + shadowBlur: 40 + } + }, + axisLabel: { // åæ ‡è½´å°æ ‡è®° + textStyle: { // 属性lineStyleæŽ§åˆ¶çº¿æ¡æ ·å¼ + fontWeight: 'bolder', + color: '#fff', + shadowColor : '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 40, + fontStyle: 'italic', + fontSize:scope.panel.fontsize + } + }, + axisTick: { // åæ ‡è½´å°æ ‡è®° + length :18, // 属性length控制线长 + lineStyle: { // 属性lineStyleæŽ§åˆ¶çº¿æ¡æ ·å¼ + color: 'auto', + shadowColor : '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 40 + } + }, + splitLine: { // 分隔线 + length :28, // 属性length控制线长 + lineStyle: { // 属性lineStyle(详è§lineStyleï¼‰æŽ§åˆ¶çº¿æ¡æ ·å¼ + width:4, + color: '#fff', + shadowColor : '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 40 + } + }, + pointer: { // 分隔线 + length:'90%', + width:3 + }, + itemStyle:{ + normal:{ + color:'#fff', + shadowColor: '#f55351', + shadowBlur: 30, + borderWidth:2, + borderColor: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, color: 'red' // 0% 处的颜色 + }, { + offset: 0.7, color: '#f8750d' // 100% 处的颜色 + },{ + offset: 1, color: '#fff' // 100% 处的颜色 + }], false) + }, + emphasis:{ + color:'#fff', + shadowColor: '#fff', + shadowBlur: 30, + borderWidth:2, + borderColor: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, color: 'red' // 0% 处的颜色 + }, { + offset: 0.7, color: '#50d1f1' // 100% 处的颜色 + },{ + offset: 1, color: '#fff' // 100% 处的颜色 + }], false) + + } + }, + title : { + textStyle: { // 其余属性默认使用全局文本样å¼ï¼Œè¯¦è§TEXTSTYLE + fontWeight: 'bolder', + fontSize: scope.panel.fontsize+20, + fontStyle: 'italic', + color: '#fff', + shadowColor : '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 40 + } + }, + detail : { + formatter:'{value}%', + // x, y,å•ä½px + textStyle: { // 其余属性默认使用全局文本样å¼ï¼Œè¯¦è§TEXTSTYLE + fontWeight: 'bolder', + color: '#fff', + fontSize:scope.panel.fontsize+10 + } + }, + data:[{value: APdex, name: 'Health State'}] + } + + ] +}; + + + // 使用刚指定的é…ç½®é¡¹å’Œæ•°æ®æ˜¾ç¤ºå›¾è¡¨ã€‚ + myChart.setOption(option); + } + + + + + + + + // Populate legend + + + } catch(e) { + elem.text(e); + } + + } + + elem.bind("plotclick", function (event, pos, object) { + if(object) { + scope.build_search(scope.data[object.seriesIndex]); + scope.panel.lastColor = object.series.color; + } + }); + + var $tooltip = $('
'); + elem.bind("plothover", function (event, pos, item) { + if (item) { + var value = scope.panel.chart === 'bar' ? item.datapoint[1] : item.datapoint[1][0][1]; + // if (scope.panel.mode === 'count') { + // value = value.toFixed(0); + // } else { + // value = value.toFixed(scope.panel.decimal_points); + // } + $tooltip + .html( + kbn.query_color_dot(item.series.color, 20) + ' ' + + item.series.label + " (" + dashboard.numberWithCommas(value.toFixed(scope.panel.decimal_points)) +")" + ) + .place_tt(pos.pageX, pos.pageY); + } else { + $tooltip.remove(); + } + }); + + } + }; + }); + +}); diff --git a/src/app/panels/bmwdashboard/timeSeries.js b/src/app/panels/bmwdashboard/timeSeries.js new file mode 100644 index 000000000..96054fa7d --- /dev/null +++ b/src/app/panels/bmwdashboard/timeSeries.js @@ -0,0 +1,179 @@ +define([ + 'underscore', + './interval' +], +function (_, Interval) { + 'use strict'; + + var ts = {}; + + // map compatable parseInt + function base10Int(val) { + return parseInt(val, 10); + } + + // trim the ms off of a time, but return it with empty ms. + function getDatesTime(date) { + return Math.floor(date.getTime() / 1000)*1000; + } + + /** + * Certain graphs require 0 entries to be specified for them to render + * properly (like the line graph). So with this we will caluclate all of + * the expected time measurements, and fill the missing ones in with 0 + * @param {object} opts An object specifying some/all of the options + * + * OPTIONS: + * @opt {string} interval The interval notion describing the expected spacing between + * each data point. + * @opt {date} start_date (optional) The start point for the time series, setting this and the + * end_date will ensure that the series streches to resemble the entire + * expected result + * @opt {date} end_date (optional) The end point for the time series, see start_date + * @opt {string} fill_style Either "minimal", or "all" describing the strategy used to zero-fill + * the series. + */ + ts.ZeroFilled = function (opts) { + opts = _.defaults(opts, { + interval: '10m', + start_date: null, + end_date: null, + fill_style: 'minimal' + }); + + // the expected differenece between readings. + this.interval = new Interval(opts.interval); + + // will keep all values here, keyed by their time + this._data = {}; + this.start_time = opts.start_date && getDatesTime(opts.start_date); + this.end_time = opts.end_date && getDatesTime(opts.end_date); + this.opts = opts; + }; + + /** + * Add a row + * @param {int} time The time for the value, in + * @param {any} value The value at this time + */ + ts.ZeroFilled.prototype.addValue = function (time, value) { + if (time instanceof Date) { + time = getDatesTime(time); + } else { + time = base10Int(time); + } + if (!isNaN(time)) { + this._data[time] = (_.isUndefined(value) ? 0 : value); + } + this._cached_times = null; + }; + + /** + * Get an array of the times that have been explicitly set in the series + * @param {array} include (optional) list of timestamps to include in the response + * @return {array} An array of integer times. + */ + ts.ZeroFilled.prototype.getOrderedTimes = function (include) { + var times = _.map(_.keys(this._data), base10Int); + if (_.isArray(include)) { + times = times.concat(include); + } + return _.uniq(times.sort(function (a, b) { + // decending numeric sort + return a - b; + }), true); + }; + + /** + * return the rows in the format: + * [ [time, value], [time, value], ... ] + * + * Heavy lifting is done by _get(Min|All)FlotPairs() + * @param {array} required_times An array of timestamps that must be in the resulting pairs + * @return {array} + */ + ts.ZeroFilled.prototype.getFlotPairs = function (required_times) { + var times = this.getOrderedTimes(required_times), + strategy, + pairs; + + if(this.opts.fill_style === 'all') { + strategy = this._getAllFlotPairs; + } else { + strategy = this._getMinFlotPairs; + } + + pairs = _.reduce( + times, // what + strategy, // how + [], // where + this // context + ); + + // if the first or last pair is inside either the start or end time, + // add those times to the series with null values so the graph will stretch to contain them. + if (this.start_time && (pairs.length === 0 || pairs[0][0] > this.start_time)) { + pairs.unshift([this.start_time, null]); + } + if (this.end_time && (pairs.length === 0 || pairs[pairs.length - 1][0] < this.end_time)) { + pairs.push([this.end_time, null]); + } + + return pairs; + }; + + /** + * ** called as a reduce stragegy in getFlotPairs() ** + * Fill zero's on either side of the current time, unless there is already a measurement there or + * we are looking at an edge. + * @return {array} An array of points to plot with flot + */ + ts.ZeroFilled.prototype._getMinFlotPairs = function (result, time, i, times) { + var next, expected_next, prev, expected_prev; + + // check for previous measurement + if (i > 0) { + prev = times[i - 1]; + expected_prev = this.interval.before(time); + if (prev < expected_prev) { + result.push([expected_prev, 0]); + } + } + + // add the current time + result.push([ time, this._data[time] || 0 ]); + + // check for next measurement + if (times.length > i) { + next = times[i + 1]; + expected_next = this.interval.after(time); + if (next > expected_next) { + result.push([expected_next, 0]); + } + } + + return result; + }; + + /** + * ** called as a reduce stragegy in getFlotPairs() ** + * Fill zero's to the right of each time, until the next measurement is reached or we are at the + * last measurement + * @return {array} An array of points to plot with flot + */ + ts.ZeroFilled.prototype._getAllFlotPairs = function (result, time, i, times) { + var next, expected_next; + + result.push([ times[i], this._data[times[i]] || 0 ]); + next = times[i + 1]; + expected_next = this.interval.after(time); + for(; times.length > i && next > expected_next; expected_next = this.interval.after(expected_next)) { + result.push([expected_next, 0]); + } + + return result; + }; + + + return ts; +}); \ No newline at end of file diff --git a/src/app/panels/bn/editor.html b/src/app/panels/bn/editor.html new file mode 100644 index 000000000..8661b3dd5 --- /dev/null +++ b/src/app/panels/bn/editor.html @@ -0,0 +1,27 @@ +
+ + +
Tooltip Settings
+
+
+ + +
+
\ No newline at end of file diff --git a/src/app/panels/bn/module.html b/src/app/panels/bn/module.html new file mode 100644 index 000000000..06df9dbab --- /dev/null +++ b/src/app/panels/bn/module.html @@ -0,0 +1,45 @@ +
+ + + + +
+
diff --git a/src/app/panels/bn/module.js b/src/app/panels/bn/module.js new file mode 100644 index 000000000..f23aadc8d --- /dev/null +++ b/src/app/panels/bn/module.js @@ -0,0 +1,588 @@ +/* + + ## Anomaly Detection + + ### Parameters + * auto_int :: Auto calculate data point interval? + * resolution :: If auto_int is enables, shoot for this many data points, rounding to + sane intervals + * interval :: Datapoint interval in elasticsearch date math format (eg 1d, 1w, 1y, 5y) + * fill :: Only applies to line charts. Level of area shading from 0-10 + * linewidth :: Only applies to line charts. How thick the line should be in pixels + While the editor only exposes 0-10, this can be any numeric value. + Set to 0 and you'll get something like a scatter plot + * timezone :: This isn't totally functional yet. Currently only supports browser and utc. + browser will adjust the x-axis labels to match the timezone of the user's + browser + * spyable :: Dislay the 'eye' icon that show the last elasticsearch query + * zoomlinks :: Show the zoom links? + * bars :: Show bars in the chart + * stack :: Stack multiple queries. This generally a crappy way to represent things. + You probably should just use a line chart without stacking + * points :: Should circles at the data points on the chart + * lines :: Line chart? Sweet. + * legend :: Show the legend? + * x-axis :: Show x-axis labels and grid lines + * y-axis :: Show y-axis labels and grid lines + * interactive :: Allow drag to select time range + + */ +define([ + 'angular', + 'app', + 'jquery', + 'underscore', + 'kbn', + 'moment', + 'gojs' + ], + function (angular, app, $, _, kbn, moment, timeSeries) { + 'use strict'; + var module = angular.module('kibana.panels.bn', []); + app.useModule(module); + + var DEBUG = true; + console.log('DEBUG : ' + DEBUG); + module.controller('bn', function($scope, $q, $http, querySrv, dashboard, filterSrv, alertSrv) { + $scope.panelMeta = { + modals : [ + { + description: "Inspect", + icon: "icon-info-sign", + partial: "app/partials/inspector.html", + show: $scope.panel.spyable + } + ], + editorTabs : [ + { + title:'Queries', + src:'app/partials/querySelect.html' + } + ], + status : "Stable", + description : "A bucketed time series chart of the current query, including all applied time and non-time filters, when used in count mode. Uses Solr’s facet.range query parameters. In values mode, it plots the value of a specific field over time, and allows the user to group field values by a second field." + }; + + // Set and populate defaults + var _d = { + mode : 'value', + queries : { + mode : 'all', + ids : [], + query : '*:*', + custom : '' + }, + max_rows : 1000, // maximum number of rows returned from Solr (also use this for group.limit to simplify UI setting) + reverse : 0, + group_field : null, + auto_int : true, + total_first : '%', + fontsize : 20, + field_color : '#209bf8', + resolution : 100, + value_sort : 'rs_timestamp', + interval : '5m', + intervals : ['auto','1s','1m','5m','10m','30m','1h','3h','12h','1d','1w','1M','1y'], + fill : 0, + linewidth : 3, + chart : 'stacking', + chartColors : ['#209bf8', '#f4d352','#ccf452','#8cf452','#3cee2b','#f467d8','#2fd7ee'], + timezone : 'browser', // browser, utc or a standard timezone + spyable : true, + zoomlinks : true, + bars : true, + stack : true, + label : true, + points : false, + lines : false, + lines_smooth: false, // Enable 'smooth line' mode by removing zero values from the plot. + legend : true, + 'x-axis' : true, + 'y-axis' : true, + percentage : false, + interactive : true, + options : true, + show_queries: true, + tooltip : { + value_type: 'cumulative', + query_as_alias: false + }, + jobid : '', + job_status: 'Ready', + }; + + _.defaults($scope.panel,_d); + + $scope.init = function() { + // Hide view options by default + if (DEBUG) console.log('init'); + $scope.options = false; + $scope.$on('refresh',function(){ + $scope.get_data(); + }); + + $scope.get_data(); + + }; + + $scope.set_interval = function(interval) { + if(interval !== 'auto') { + $scope.panel.auto_int = false; + $scope.panel.interval = interval; + } else { + $scope.panel.auto_int = true; + } + }; + + $scope.interval_label = function(interval) { + return $scope.panel.auto_int && interval === $scope.panel.interval ? interval+" (auto)" : interval; + }; + + $scope.set_refresh = function (state) { + $scope.refresh = state; + // if 'count' mode is selected, set decimal_points to zero automatically. + if ($scope.panel.mode === 'count') { + $scope.panel.decimal_points = 0; + } + $scope.get_data(); + }; + + /** + * The time range effecting the panel + * @return {[type]} [description] + */ + $scope.get_time_range = function () { + var range = $scope.range = filterSrv.timeRange('min'); + return range; + }; + + $scope.get_interval = function () { + var interval = $scope.panel.interval, + range; + if ($scope.panel.auto_int) { + range = $scope.get_time_range(); + if (range) { + interval = kbn.secondsToHms( + kbn.calculate_interval(range.from, range.to, $scope.panel.resolution, 0) / 1000 + ); + } + } + $scope.panel.interval = interval || '10m'; + return $scope.panel.interval; + }; + + $scope.build_anomaly_query = function(filetype, isForExport) { + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + } + if (dashboard.current.anomaly_fq) { + fq = fq + '&' + dashboard.current.anomaly_fq; + } + var wt_json = '&wt=' + filetype; + var rows_limit = isForExport ? '&rows=0' : ''; // for terms, we do not need the actual response doc, so set rows=0 + var facet = ''; + return querySrv.getORquery() + wt_json + rows_limit + fq + facet + ($scope.panel.queries.custom !== null ? $scope.panel.queries.custom : ''); + }; + + /** + * Fetch the data for a chunk of a queries results. Multiple segments occur when several indicies + * need to be consulted (like timestamped logstash indicies) + * + * The results of this function are stored on the scope's data property. This property will be an + * array of objects with the properties info, time_series, and hits. These objects are used in the + * render_panel function to create the historgram. + * + * !!! Solr does not need to fetch the data in chunk because it uses a facet search and retrieve + * !!! all events from a single query. + * + * @param {number} segment The segment count, (0 based) + * @param {number} query_id The id of the query, generated on the first run and passed back when + * this call is made recursively for more segments + */ + $scope.get_data = function(segment, query_id) { + if (DEBUG) console.log('get data start.'); + if (_.isUndefined(segment)) { + segment = 0; + } + delete $scope.panel.error; + + // Make sure we have everything for the request to complete + if(dashboard.indices.length === 0) { + return; + } + var _range = $scope.get_time_range(); + var _interval = $scope.get_interval(_range); + + if ($scope.panel.auto_int) { + $scope.panel.interval = kbn.secondsToHms( + kbn.calculate_interval(_range.from,_range.to,$scope.panel.resolution,0)/1000); + } + + $scope.panelMeta.loading = true; + + // Solr + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + var request = $scope.sjs.Request().indices(dashboard.indices[segment]); + // $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + + + $scope.panel.queries.query = ""; + // Build the query + _.each($scope.panel.queries.ids, function(id) { + var query = $scope.sjs.FilteredQuery( + querySrv.getEjsObj(id), + filterSrv.getBoolFilter(filterSrv.ids) + ); + + var facet = $scope.sjs.DateHistogramFacet(id); + + }); + + if(_.isNull($scope.panel.value_field)) { + $scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified"; + return; + } + + + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + } + + var time_field = filterSrv.getTimeField(); + var start_time = filterSrv.getStartTime(); + var end_time = filterSrv.getEndTime(); + + $scope.panel.start_time = start_time; + $scope.panel.end_time = end_time; + + // facet.range.end does NOT accept * as a value, need to convert it to NOW + if (end_time === '*') { + end_time = 'NOW'; + } + + //*********************************** 拼查询url************ + var wt_json = '&wt=json'; + // var metric_field = $scope.panel.metric_field; + //var anomaly_th = $scope.panel.anomaly_th; + var sort_field = '&sort='+'timestamp_l'+'%20asc'; + //var rows_limit = '&rows='+$scope.panel.max_rows; + // var facet = ''; + //var fl = '&fl=' + 'timestamp_l%20anomaly_value_d%20value_d'; + var fl = '&fl=' + 'nodes_s%20edges_s%20query_list'; + //fq = fq + '&fq=anomaly_value_d:[' + anomaly_th + '%20TO%20*]'; + + //*********************************** end ******************* + + var mypromises = []; + //var temp_q = 'q=' + metric_field + ':' + metric + wt_json + rows_limit + fq + facet + fl + sort_field; + var querys = []; + + var temp_q = 'q=' + 'result_s:bn' + wt_json ; + var temp_q2 = $scope.build_anomaly_query('json', false); + querys.push(temp_q); + querys.push(temp_q2); + if(DEBUG) console.log(temp_q2); + + for (var i = 0; i < querys.length; i++) { + + $scope.panel.queries.query += querys[i] + "\n"; + + if ($scope.panel.queries.custom !== null) { + request = request.setQuery(querys[i] + $scope.panel.queries.custom); + } else { + request = request.setQuery(querys[i]); + } + mypromises.push(request.doSearch()); + } + + $scope.data = []; + if (dashboard.current.services.query.ids.length >= 1) { + $q.all(mypromises).then(function(results) { + if (DEBUG) console.log(results); + $scope.panelMeta.loading = false; + // Convert facet ids to numbers + // var facetIds = _.map(_.keys(results.facets),function(k){return parseInt(k, 10);}); + //var facetIds = [0]; // Need to fix this + + // Make sure we're still on the same query/queries + // TODO: We probably DON'T NEED THIS unless we have to support multiple queries in query module. + // if ($scope.query_id === query_id && _.difference(facetIds, $scope.panel.queries.ids).length === 0) { + var time_series, hits; + for (var i = 0; i < querys.length; i++) { + if (!(_.isUndefined(results[i].error))) { + $scope.panel.error = $scope.parse_error(results[i].error.msg); + return; + } + $scope.data[i] = results[i].response.docs; + if (DEBUG) console.log($scope.data[i]); + } + // Tell the histogram directive to render. + $scope.$emit('render'); + }); + } + }; + }); + + module.directive('bnChart', function(querySrv,dashboard,filterSrv) { + return { + restrict: 'A', + link: function(scope, elem) { + + // Receive render events + scope.$on('render',function(){ + render_panel(); + }); + + // Re-render if the window is resized + angular.element(window).bind('resize', function(){ + render_panel(); + }); + + // Function for rendering panel + function render_panel() { + var plot, chartData; + var colors = []; + + // IE doesn't work without this + elem.css({height:scope.panel.height||scope.row.height}); + + // Make a clone we can operate on. + + chartData = _.clone(scope.data); + chartData = scope.panel.missing ? chartData : + _.without(chartData,_.findWhere(chartData,{meta:'missing'})); + chartData = scope.panel.other ? chartData : + _.without(chartData,_.findWhere(chartData,{meta:'other'})); + + var nodeList = JSON.parse(chartData[0][0].nodes_s); + var linkList = JSON.parse(chartData[0][0].edges_s); + if (DEBUG) console.log(chartData[1][0]); + var ad_list = []; + for (var i = 0; i < chartData[1].length; i++) { + ad_list.push(chartData[1][i].facet_name_s); + // alert(ad_list[i]); + } + + // ad_list.push("JAVAEE_Apdex"); + // ad_list.push("JAVAEE_Http_4xx"); + // ad_list.push("JAVAEE_Durations_sum"); + + // alert(ad_list); + + if (DEBUG) console.log(ad_list); + //alert(nodeList[0].key); + if (DEBUG) console.log(chartData[0][0]); + var query_list = chartData[0][0].query_list_s.split("^"); + + if(DEBUG) console.log(query_list); + for (var i = 0; i < nodeList.length; i++) { + if (checkIn(query_list[parseInt(nodeList[i].key.substr(1))], ad_list)) { + nodeList[i]["color"] = "red"; + } else { + nodeList[i]["color"] = "green"; + } + } + + + //alert(chartData); + //alert(linkList[0].to); + + // begin to drow chart + + var graph_id = scope.$id; + var go = require('gojs'); + // var metric = scope.panel.metric_field; + // var labelcolor = false; + + // if (dashboard.current.style === 'dark'){ + // labelcolor = true; + // } + + // var graph = echarts.init(dobument.getElementById(graph_id)); + + // This variation on ForceDirectedLayout does not move any selected + // Nodes + // but does move all other nodes (vertexes). + function ContinuousForceDirectedLayout() { + go.ForceDirectedLayout.call(this); + this._isObserving = false; + } + go.Diagram.inherit(ContinuousForceDirectedLayout, go.ForceDirectedLayout); + + /** @override */ + ContinuousForceDirectedLayout.prototype.isFixed = function(v) { + return v.node.isSelected; + } + + // optimization: reuse the ForceDirectedNetwork rather than re-create it + // each time + /** @override */ + ContinuousForceDirectedLayout.prototype.doLayout = function(coll) { + if (!this._isObserving) { + this._isObserving = true; + // cacheing the network means we need to recreate it if nodes or + // links have been added or removed or relinked, + // so we need to track structural model changes to discard the saved + // network. + var lay = this; + this.diagram.addModelChangedListener(function (e) { + // modelChanges include a few cases that we don't actually care + // about, such as + // "nodeCategory" or "linkToPortId", but we'll go ahead and recreate + // the network anyway. + // Also clear the network when replacing the model. + if (e.modelChange !== "" || (e.change === go.ChangedEvent.Transaction && e.propertyName === "StartingFirstTransaction")) { + lay.network = null; + } + }); + } + var net = this.network; + if (net === null) { // the first time, just create the network as + // normal + this.network = net = this.makeNetwork(coll); + } else { // but on reuse we need to update the LayoutVertex.bounds + // for selected nodes + this.diagram.nodes.each(function (n) { + var v = net.findVertex(n); + if (v !== null) v.bounds = n.actualBounds; + }); + } + // now perform the normal layout + go.ForceDirectedLayout.prototype.doLayout.call(this, coll); + // doLayout normally discards the LayoutNetwork by setting + // Layout.network to null; + // here we remember it for next time + this.network = net; + } + // end ContinuousForceDirectedLayout + + + function drawGraph(nodeDataArray, linkDataArray, graph_id) { + var $ = go.GraphObject.make; // for conciseness in defining templates + + var myDiagram = + $(go.Diagram, graph_id+"", // create a Diagram for the DIV HTML + // element + { + initialAutoScale: go.Diagram.Uniform, // an initial automatic + // zoom-to-fit + contentAlignment: go.Spot.Center, // align document to the + // center of the + // viewport + layout: + $(ContinuousForceDirectedLayout, // automatically spread + // nodes apart while + // dragging + { defaultSpringLength: 30, defaultElectricalCharge: 100 }), + // do an extra layout at the end of a move + "SelectionMoved": function(e) { e.diagram.layout.invalidateLayout(); } + }); + + // get tooltip text from the object's data + function tooltipTextConverter(node) { + //var str = "right"; + //str += "Born: " + person.birthYear; + //if (person.deathYear !== undefined) str += "\nDied: " + person.deathYear; + //if (person.reign !== undefined) str += "\nReign: " + person.reign; + var x = node.key.substr(1); + return query_list[parseInt(x)]; + } + + // define tooltips for nodes + var tooltiptemplate = + $(go.Adornment, "Auto", + $(go.Shape, "Rectangle", + { fill: "whitesmoke", stroke: "black" }), + $(go.TextBlock, + { font: "bold 16pt Helvetica, bold Arial, sans-serif", + wrap: go.TextBlock.WrapFit, + margin: 5 }, + new go.Binding("text", "", tooltipTextConverter)) + ); + + myDiagram.toolManager.draggingTool.doMouseMove = function() { + go.DraggingTool.prototype.doMouseMove.call(this); + if (this.isActive) { this.diagram.layout.invalidateLayout(); } + } + + // These nodes have text surrounded by a rounded rectangle + // whose fill color is bound to the node data. + // The user can drag a node by dragging its TextBlock label. + // Dragging from the Shape will start drawing a new link. + myDiagram.nodeTemplate = + $(go.Node, "Auto", // the whole node panel define the node's outer shape, which will surround the TextBlock + { deletable: false, toolTip: tooltiptemplate }, + $(go.Shape, "Circle", + { fill: "green", stroke: "black", spot1: new go.Spot(0, 0, 5, 5), spot2: new go.Spot(1, 1, -5, -5) }, //"CornflowerBlue" + new go.Binding("fill", "color") + ), + $(go.TextBlock, + { font: "bold 10pt helvetica, bold arial, sans-serif", textAlign: "center", maxSize: new go.Size(100, NaN) }, + new go.Binding("text", "key")), + { + click: function(e, obj) { window.selected_var=obj.part.data.key;showMessage(obj.part.data.key); }, + selectionChanged: function(part) { + var shape = part.elt(0); + if (part.isSelected) { + shape.fill = "yellow"; + } + else { + //alert(window.selected_var); + var x = window.selected_var; + if (checkIn(query_list[parseInt(x.substr(1))],ad_list)) + shape.fill = "red"; + else + shape.fill = "green"; + } + //shape.fill = part.isSelected ? "yellow" : "CornflowerBlue"; + } + } + ); + + // The link shape and arrowhead have their stroke brush data + // bound to the "color" property + myDiagram.linkTemplate = + $(go.Link, // the whole link panel + $(go.Shape, // the link shape + { stroke: "black" }), + $(go.Shape, // the arrowhead + { toArrow: "standard", stroke: null }) + ); + myDiagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray); + } + + function checkIn(x, list) { + for (var i = 0; i < list.length; i++) { + if (x == list[i]) + return true; + } + return false; + } + + function reload() { + //myDiagram.layout.network = null; + var text = myDiagram.model.toJson(); + myDiagram.model = go.Model.fromJson(text); + //myDiagram.layout = + // go.GraphObject.make(ContinuousForceDirectedLayout, // automatically spread nodes apart while dragging + // { defaultSpringLength: 30, defaultElectricalCharge: 100 }); + } + + function showMessage(s) { + //alert("klick: "+s+"."); + dashboard.current.bn_main_node = s; + dashboard.refresh(); + } + drawGraph(nodeList, linkList, graph_id); + } + } + }; + }); + + + }); diff --git a/src/app/panels/china/editor.html b/src/app/panels/china/editor.html new file mode 100644 index 000000000..4722214f7 --- /dev/null +++ b/src/app/panels/china/editor.html @@ -0,0 +1,67 @@ +
+
+ + +
+
+ + +
+
+ + +
+
+ + + +
+ +
+
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ + +
+
+ + +
+
+ +
+
Real-time (Auto-refresh)
+
+ +
+
+ + +
+
+
+
Linkage Effective
+
+ +
+ +
diff --git a/src/app/panels/china/module.html b/src/app/panels/china/module.html new file mode 100644 index 000000000..5c9aa1388 --- /dev/null +++ b/src/app/panels/china/module.html @@ -0,0 +1,96 @@ +
+ + + + + + + + + + +
+ + + + + + + + +
+
\ No newline at end of file diff --git a/src/app/panels/china/module.js b/src/app/panels/china/module.js new file mode 100644 index 000000000..4624a5934 --- /dev/null +++ b/src/app/panels/china/module.js @@ -0,0 +1,1643 @@ +/* + ## pies + + ### Parameters + * style :: A hash of css styles + * size :: top N + * arrangement :: How should I arrange the query results? 'horizontal' or 'vertical' + * chart :: Show a chart? 'none', 'bar', 'pie' + * donut :: Only applies to 'pie' charts. Punches a hole in the chart for some reason + * tilt :: Only 'pie' charts. Janky 3D effect. Looks terrible 90% of the time. + * lables :: Only 'pie' charts. Labels on the pie? +*/ +define([ + 'angular', + 'app', + 'underscore', + 'jquery', + 'kbn', + 'echarts-china', +], +function (angular, app, _, $, kbn) { + 'use strict'; + + var module = angular.module('kibana.panels.china', []); + app.useModule(module); + + module.controller('china', function($scope, $timeout, timer, querySrv, dashboard, filterSrv) { + $scope.panelMeta = { + + exportfile: true, + editorTabs : [ + {title:'Queries', src:'app/partials/querySelect.html'} + ], + status : "Stable", + description : "Displays the results of a Solr facet as a pie chart, bar chart, or a table. Newly added functionality displays min/max/mean/sum of a stats field, faceted by the Solr facet field, again as a pie chart, bar chart or a table." + }; + + // Set and populate defaults + var _d = { + queries : { + mode : 'all', + ids : [], + query : '*:*', + custom : '' + }, + mode : 'count', // mode to tell which number will be used to plot the chart. + field : '', + stats_field : '', + decimal_points : 0, // The number of digits after the decimal point + exclude : [], + missing : false, + other : false, + size : 10000, + sortBy : 'count', + order : 'descending', + linkage_id:'a', + logAxis : false, + display:'block', + isEN:false, + icon:"icon-caret-down", + chart : 'china_map', + exportSize : 10000, + lastColor : '', + spyable : true, + show_queries:true, + error : '', + chartColors : querySrv.colors, + refresh: { + enable: false, + interval: 2 + } + }; + _.defaults($scope.panel,_d); + + $scope.init = function () { + $scope.hits = 0; + //$scope.testMultivalued(); + + // Start refresh timer if enabled + if ($scope.panel.refresh.enable) { + $scope.set_timer($scope.panel.refresh.interval); + } + + $scope.$on('refresh',function(){ + $scope.get_data(); + }); + + $scope.get_data(); + }; + + $scope.testMultivalued = function() { + if($scope.panel.field && $scope.fields.typeList[$scope.panel.field] && $scope.fields.typeList[$scope.panel.field].schema.indexOf("M") > -1) { + $scope.panel.error = "Can't proceed with Multivalued field"; + return; + } + + if($scope.panel.stats_field && $scope.fields.typeList[$scope.panel.stats_field].schema.indexOf("M") > -1) { + $scope.panel.error = "Can't proceed with Multivalued field"; + return; + } + }; + + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; + + /** + * + * + * @param {String} filetype -'json', 'xml', 'csv' + */ + $scope.build_query = function(filetype, isForExport) { + + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + } + var wt_json = '&wt=' + filetype; + var rows_limit = isForExport ? '&rows=0' : ''; // for pies, we do not need the actual response doc, so set rows=0 + var facet = ''; + + if ($scope.panel.mode === 'count') { + facet = '&facet=true&facet.field=' + $scope.panel.field + '&facet.limit=' + $scope.panel.size + '&facet.missing=true'; + } else { + // if mode != 'count' then we need to use stats query + // stats does not support something like facet.limit, so we have to sort and limit the results manually. + facet = '&stats=true&stats.facet=' + $scope.panel.field + '&stats.field=' + $scope.panel.stats_field + '&facet.missing=true'; + } + facet += '&f.' + $scope.panel.field + '.facet.sort=' + ($scope.panel.sortBy || 'count'); + + var exclude_length = $scope.panel.exclude.length; + var exclude_filter = ''; + if(exclude_length > 0){ + for (var i = 0; i < exclude_length; i++) { + if($scope.panel.exclude[i] !== "") { + exclude_filter += '&fq=-' + $scope.panel.field +":"+ $scope.panel.exclude[i]; + } + } + } + + return querySrv.getORquery() + wt_json + rows_limit + fq + exclude_filter + facet + ($scope.panel.queries.custom != null ? $scope.panel.queries.custom : ''); + }; + + $scope.exportfile = function(filetype) { + + var query = this.build_query(filetype, true); + + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + var request = $scope.sjs.Request().indices(dashboard.indices), + response; + + request.setQuery(query); + + response = request.doSearch(); + + // Populate scope when we have results + response.then(function(response) { + kbn.download_response(response, filetype, "china"); + }); + }; + + $scope.set_timer = function(refresh_interval) { + $scope.panel.refresh.interval = refresh_interval; + if (_.isNumber($scope.panel.refresh.interval)) { + timer.cancel($scope.refresh_timer); + $scope.realtime(); + } else { + timer.cancel($scope.refresh_timer); + } + }; + + $scope.realtime = function() { + if ($scope.panel.refresh.enable) { + timer.cancel($scope.refresh_timer); + + $scope.refresh_timer = timer.register($timeout(function() { + $scope.realtime(); + $scope.get_data(); + }, $scope.panel.refresh.interval*1000)); + } else { + timer.cancel($scope.refresh_timer); + } + }; + + $scope.get_data = function() { + if(($scope.panel.linkage_id === dashboard.current.linkage_id)||dashboard.current.enable_linkage){ + // Make sure we have everything for the request to complete + if (dashboard.indices.length === 0) { + return; + } + + delete $scope.panel.error; + $scope.panelMeta.loading = true; + var request, results; + + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + request = $scope.sjs.Request().indices(dashboard.indices); + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + + // Populate the inspector panel + $scope.inspector = angular.toJson(JSON.parse(request.toString()), true); + + var query = this.build_query('json', false); + + // Set the panel's query + $scope.panel.queries.query = query; + + request.setQuery(query); + + results = request.doSearch(); + + // Populate scope when we have results + results.then(function (results) { + // Check for error and abort if found + if (!(_.isUndefined(results.error))) { + $scope.panel.error = $scope.parse_error(results.error.msg); + $scope.data = []; + $scope.panelMeta.loading = false; + $scope.$emit('render'); + return; + } + + // Function for validating HTML color by assign it to a dummy
+ // and let the browser do the work of validation. + var isValidHTMLColor = function (color) { + // clear attr first, before comparison + $('#colorTest').removeAttr('style'); + var valid = $('#colorTest').css('color'); + $('#colorTest').css('color', color); + + if (valid === $('#colorTest').css('color')) { + return false; + } else { + return true; + } + }; + + // Function for customizing chart color by using field values as colors. + var addSliceColor = function (slice, color) { + if ($scope.panel.useColorFromField && isValidHTMLColor(color)) { + slice.color = color; + } + return slice; + }; + + var sum = 0; + var k = 0; + var missing = 0; + $scope.panelMeta.loading = false; + $scope.hits = results.response.numFound; + $scope.data = []; + + if ($scope.panel.mode === 'count') { + // In count mode, the y-axis min should be zero because count value cannot be negative. + $scope.yaxis_min = 0; + _.each(results.facet_counts.facet_fields, function (v) { + for (var i = 0; i < v.length; i++) { + var term = v[i]; + i++; + var count = v[i]; + sum += count; + if (term === null) { + missing = count; + } else { + // if count = 0, do not add it to the chart, just skip it + if (count === 0) { + continue; + } + var slice = {label: term, data: [[k, count]], actions: true}; + slice = addSliceColor(slice, term); + $scope.data.push(slice); + } + } + }); + } else { + // In stats mode, set y-axis min to null so jquery.flot will set the scale automatically. + $scope.yaxis_min = null; + _.each(results.stats.stats_fields[$scope.panel.stats_field].facets[$scope.panel.field], function (stats_obj, facet_field) { + var slice = {label: facet_field, data: [[k, stats_obj[$scope.panel.mode]]], actions: true}; + $scope.data.push(slice); + }); + } + // Sort the results + $scope.data = _.sortBy($scope.data, function (d) { + return $scope.panel.sortBy === 'index' ? d.label : d.data[0][1]; + }); + if ($scope.panel.order === 'descending') { + $scope.data.reverse(); + } + + // Slice it according to panel.size, and then set the x-axis values with k. + $scope.data = $scope.data.slice(0, $scope.panel.size); + _.each($scope.data, function (v) { + v.data[0][0] = k; + k++; + }); + + if ($scope.panel.field && $scope.fields.typeList[$scope.panel.field] && $scope.fields.typeList[$scope.panel.field].schema.indexOf("T") > -1) { + $scope.hits = sum; + } + + $scope.data.push({ + label: 'Missing field', + // data:[[k,results.facets.pies.missing]],meta:"missing",color:'#aaa',opacity:0}); + // TODO: Hard coded to 0 for now. Solr faceting does not provide 'missing' value. + data: [[k, missing]], meta: "missing", color: '#aaa', opacity: 0 + }); + $scope.data.push({ + label: 'Other values', + // data:[[k+1,results.facets.pies.other]],meta:"other",color:'#444'}); + // TODO: Hard coded to 0 for now. Solr faceting does not provide 'other' value. + data: [[k + 1, $scope.hits - sum]], meta: "other", color: '#444' + }); + + $scope.$emit('render'); + }); + } + }; + + $scope.build_search = function(term,negate) { + if(_.isUndefined(term.meta)) { + filterSrv.set({type:'china',field:$scope.panel.field,value:term.label, + mandate:(negate ? 'mustNot':'must')}); + } else if(term.meta === 'missing') { + filterSrv.set({type:'exists',field:$scope.panel.field, + mandate:(negate ? 'must':'mustNot')}); + } else { + return; + } + dashboard.refresh(); + }; + + $scope.set_refresh = function (state) { + $scope.refresh = state; + // if 'count' mode is selected, set decimal_points to zero automatically. + if ($scope.panel.mode === 'count') { + $scope.panel.decimal_points = 0; + } + }; + + $scope.close_edit = function() { + // Start refresh timer if enabled + if ($scope.panel.refresh.enable) { + $scope.set_timer($scope.panel.refresh.interval); + } + + if ($scope.refresh) { + // $scope.testMultivalued(); + $scope.get_data(); + } + $scope.refresh = false; + $scope.$emit('render'); + }; + + $scope.showMeta = function(term) { + if(_.isUndefined(term.meta)) { + return true; + } + if(term.meta === 'other' && !$scope.panel.other) { + return false; + } + if(term.meta === 'missing' && !$scope.panel.missing) { + return false; + } + return true; + }; + + }); + + module.directive('chinaChart', function(querySrv,dashboard,filterSrv) { + return { + restrict: 'A', + + link: function(scope, elem) { + + // Receive render events + scope.$on('render',function(){ + render_panel(); + }); + + // Re-render if the window is resized + angular.element(window).bind('resize', function(){ + render_panel(); + }); + + // Function for rendering panel + function render_panel() { + var myChart; + var chartData; + var renderBrushed =function(){}; + var colors = []; + + // IE doesn't work without this + elem.css({height:scope.panel.height||scope.row.height}); + + // Make a clone we can operate on. + + chartData = _.clone(scope.data); + chartData = scope.panel.missing ? chartData : + _.without(chartData,_.findWhere(chartData,{meta:'missing'})); + chartData = scope.panel.other ? chartData : + _.without(chartData,_.findWhere(chartData,{meta:'other'})); + + if (filterSrv.idsByTypeAndField('china',scope.panel.field).length > 0) { + colors.push(scope.panel.lastColor); + } else { + colors = scope.panel.chartColors; + } + + var option_nodata = { + series: [{ + + type: 'wordCloud', + //size: ['9%', '99%'], + sizeRange: [50, 50], + //textRotation: [0, 45, 90, -45], + rotationRange: [0, 0], + //shape: 'circle', + textPadding: 0, + autoSize: { + enable: true, + minSize: 6 + }, + textStyle: { + normal: { + color: '#1a93f9' + }, + emphasis: { + shadowBlur: 10, + shadowColor: '#333' + } + }, + data: [{ + name: "NO DATA", + value: 1 + }] + }] +}; + + + var idd = scope.$id; + //var echarts = require('echarts'); + + require(['echarts'], function(ec){ + var echarts = ec; + if(myChart) { + myChart.dispose(); + } + // Populate element + try { + var labelcolor = false; + if (dashboard.current.style === 'dark'){ + labelcolor = true; + } + // Add plot to scope so we can build out own legend + + var arrdata = []; + + var arrlabel = []; + var radarmax = 0; + for (var i = 0; i < chartData.length; i++) { + arrlabel[i] = chartData[i].label; + arrdata[i] = {name:chartData[i].label,value:chartData[i].data[0][1]}; + + if (chartData[i].data[0][1]>radarmax){ + radarmax = chartData[i].data[0][1]; + } + + + } + + var geoCoordMap={'香港':[114.08,22.2],'澳门':[113.33,22.13],'å°åŒ—市':[121.5,25.03],'基隆市':[121.73,25.13],'å°ä¸­å¸‚':[120.67,24.15],'å°å—市':[120.2,23.0],'宜兰县':[121.75,24.77], + '桃园县':[121.3,24.97],'苗栗县':[120.8,24.53],'å°ä¸­åŽ¿':[120.72,24.25],'彰化县':[120.53,24.08], + 'å—æŠ•åŽ¿':[120.67,23.92],'云林县':[120.53,23.72],'å°å—县':[120.32,23.32],'高雄县':[120.37,22.63], + 'å±ä¸œåŽ¿':[120.48,22.67],'å°ä¸œåŽ¿':[121.15,22.75],'花莲县':[121.6,23.98],'澎湖县':[119.58,23.58], + '石家庄市':[114.52,38.05],'å”山市':[118.2,39.63],'秦皇岛市':[119.6,39.93],'邯郸市':[114.48,36.62], + 'é‚¢å°å¸‚':[114.48,37.07],'ä¿å®šå¸‚':[115.47,38.87],'å¼ å®¶å£å¸‚':[114.88,40.82],'承德市':[117.93,40.97], + '沧州市':[116.83,38.3],'廊åŠå¸‚':[116.7,39.52],'衡水市':[115.68,37.73],'太原市':[112.55,37.87], + '大åŒå¸‚':[113.3,40.08],'阳泉市':[113.57,37.85],'长治市':[113.12,36.2],'晋城市':[112.83,35.5], + '朔州市':[112.43,39.33],'晋中市':[112.75,37.68],'è¿åŸŽå¸‚':[110.98,35.02],'忻州市':[112.73,38.42], + '临汾市':[111.52,36.08],'啿¢å¸‚':[111.13,37.52],'呼和浩特市':[111.73,40.83],'包头市':[109.83,40.65], + '乌海市':[106.82,39.67],'赤峰市':[118.92,42.27],'通辽市':[122.27,43.62],'鄂尔多斯市':[109.8,39.62], + '呼伦è´å°”市':[119.77,49.22],'巴彦淖尔市':[107.42,40.75],'乌兰察布市':[113.12,40.98],'兴安盟':[122.05,46.08], + '锡林郭勒盟':[116.07,43.95],'阿拉善盟':[105.67,38.83],'沈阳市':[123.43,41.8],'大连市':[121.62,38.92],'éžå±±å¸‚':[122.98,41.1],'抚顺市':[123.98,41.88],'本溪市':[123.77,41.3], + '丹东市':[124.38,40.13],'锦州市':[121.13,41.1],'è¥å£å¸‚':[122.23,40.67],'阜新市':[121.67,42.02], + '辽阳市':[123.17,41.27],'盘锦市':[122.07,41.12],'é“岭市':[123.83,42.28],'æœé˜³å¸‚':[120.45,41.57], + '葫芦岛市':[120.83,40.72],'长春市':[125.32,43.9],'剿ž—市':[126.55,43.83],'四平市':[124.35,43.17], + 'è¾½æºå¸‚':[125.13,42.88],'通化市':[125.93,41.73],'白山市':[126.42,41.93],'æ¾åŽŸå¸‚':[124.82,45.13], + '白城市':[122.83,45.62],'延边州':[129.5,42.88],'哈尔滨市':[126.53,45.8],'é½é½å“ˆå°”市':[123.95,47.33], + '鸡西市':[130.97,45.3],'鹤岗市':[130.27,47.33],'åŒé¸­å±±å¸‚':[131.15,46.63],'大庆市':[125.03,46.58], + '伊春市':[128.9,47.73],'佳木斯市':[130.37,46.82],'ä¸ƒå°æ²³å¸‚':[130.95,45.78],'牡丹江市':[129.6,44.58], + '黑河市':[127.48,50.25],'绥化市':[126.98,46.63],'大兴安岭地区':[124.12,50.42],'å—京市':[118.78,32.07], + '无锡市':[120.3,31.57],'å¾å·žå¸‚':[117.18,34.27],'常州市':[119.95,31.78],'è‹å·žå¸‚':[120.58,31.3], + 'å—通市':[120.88,31.98],'连云港市':[119.22,34.6],'淮安市':[119.02,33.62],'ç›åŸŽå¸‚':[120.15,33.35], + '扬州市':[119.4,32.4],'镇江市':[119.45,32.2],'泰州市':[119.92,32.45],'宿è¿å¸‚':[118.28,33.97], + 'æ­å·žå¸‚':[120.15,30.28],'宿³¢å¸‚':[121.55,29.88],'温州市':[120.7,28.0],'嘉兴市':[120.75,30.75], + '湖州市':[120.08,30.9],'ç»å…´å¸‚':[120.57,30.0],'金åŽå¸‚':[119.65,29.08],'衢州市':[118.87,28.93], + '舟山市':[122.2,30.0],'å°å·žå¸‚':[121.43,28.68],'丽水市':[119.92,28.45],'åˆè‚¥å¸‚':[117.25,31.83], + '芜湖市':[118.38,31.33],'蚌埠市':[117.38,32.92],'æ·®å—市':[117.0,32.63],'马éžå±±å¸‚':[118.5,31.7], + '淮北市':[116.8,33.95],'铜陵市':[117.82,30.93],'安庆市':[117.05,30.53],'黄山市':[118.33,29.72], + 'æ»å·žå¸‚':[118.32,32.3],'阜阳市':[115.82,32.9],'宿州市':[116.98,33.63],'巢湖市':[117.87,31.6], + '六安市':[116.5,31.77],'亳州市':[115.78,33.85],'池州市':[117.48,30.67],'宣城市':[118.75,30.95], + 'ç¦å·žå¸‚':[119.3,26.08],'厦门市':[118.08,24.48],'莆田市':[119.0,25.43],'三明市':[117.62,26.27], + '泉州市':[118.67,24.88],'漳州市':[117.65,24.52],'å—平市':[118.17,26.65],'龙岩市':[117.03,25.1], + 'å®å¾·å¸‚':[119.52,26.67],'å—æ˜Œå¸‚':[115.85,28.68],'景德镇市':[117.17,29.27],'è乡市':[113.85,27.63],'乿±Ÿå¸‚':[116.0,29.7],'新余市':[114.92,27.82],'鹰潭市':[117.07,28.27],'赣州市':[114.93,25.83],'å‰å®‰å¸‚':[114.98,27.12],'宜春市':[114.38,27.8],'抚州市':[116.35,28.0],'上饶市':[117.97,28.45],'济å—市':[116.98,36.67],'é’岛市':[120.38,36.07],'æ·„åšå¸‚':[118.05,36.82],'枣庄市':[117.32,34.82],'东è¥å¸‚':[118.67,37.43],'烟å°å¸‚':[121.43,37.45],'æ½åŠå¸‚':[119.15,36.7],'èæ³½å¸‚':[115.26,35.14],'济å®å¸‚':[116.58,35.42],'泰安市':[117.08,36.2],'卿µ·å¸‚':[122.12,37.52],'日照市':[119.52,35.42],'莱芜市':[117.67,36.22], + '临沂市':[118.35,35.05],'德州市':[116.3,37.45],'èŠåŸŽå¸‚':[115.98,36.45],'滨州市':[117.97,37.38],'郑州市':[113.62,34.75],'å¼€å°å¸‚':[114.3,34.8],'洛阳市':[112.45,34.62],'平顶山市':[113.18,33.77],'安阳市':[114.38,36.1],'鹤å£å¸‚':[114.28,35.75],'新乡市':[113.9,35.3],'焦作市':[113.25,35.22],'济æºå¸‚':[112.58,35.07],'濮阳市':[115.03,35.77],'许昌市':[113.85,34.03],'漯河市':[114.02,33.58],'三门峡市':[111.2,34.78],'å—阳市':[112.52,33.0],'商丘市':[115.65,34.45],'信阳市':[114.07,32.13],'周å£å¸‚':[114.65,33.62],'驻马店市':[114.02,32.98],'神农架林区':[110.67,31.75],'武汉市':[114.3,30.6],'黄石市':[115.03,30.2],'å堰市':[110.78,32.65],'宜昌市':[111.28,30.7],'鄂州市':[114.88,30.4],'è†é—¨å¸‚':[112.2,31.03],'å­æ„Ÿå¸‚':[113.92,30.93],'è†å·žå¸‚':[112.23,30.33],'黄冈市':[114.87,30.45],'å’¸å®å¸‚':[114.32,29.85],'éšå·žå¸‚':[113.37,31.72],'æ©æ–½å·ž':[109.47,30.3],'仙桃市':[113.45,30.37],'潜江市':[112.88,30.42],'天门市':[113.17,30.67],'长沙市':[112.93,28.23], + '株洲市':[113.13,27.83],'湘潭市':[112.93,27.83],'衡阳市':[112.57,26.9],'邵阳市':[111.47,27.25], + '岳阳市':[113.12,29.37],'常德市':[111.68,29.05],'张家界市':[110.47,29.13],'益阳市':[112.32,28.6], + '郴州市':[113.02,25.78],'永州市':[111.62,26.43],'怀化市':[110.0,27.57],'娄底市':[112.0,27.73], + '湘西州':[109.73,28.32],'广州市': [113.5107,23.2196],'韶关市':[113.6,24.82],'深圳市':[114.05,22.55], + 'ç æµ·å¸‚':[113.57,22.27],'汕头市':[116.68,23.35],'佛山市':[113.12,23.02],'江门市':[113.08,22.58], + '湛江市':[110.35,21.27],'茂å市':[110.92,21.67],'肇庆市':[112.47,23.05],'惠州市':[114.42,23.12], + '梅州市':[116.12,24.28],'汕尾市':[115.37,22.78],'æ²³æºå¸‚':[114.7,23.73],'阳江市':[111.98,21.87], + '清远市':[113.03,23.7],'东莞市':[113.75,23.05],'中山市':[113.38,22.52],'潮州市':[116.62,23.67], + 'æ­é˜³å¸‚':[116.37,23.55],'云浮市':[112.03,22.92],'å—å®å¸‚':[108.37,22.82],'柳州市':[109.42,24.33], + '防城港市':[108.35,21.7],'æ¥å®¾å¸‚':[109.23,23.73],'崇左市':[107.37,22.4],'桂林市':[110.28,25.28], + '梧州市':[111.27,23.48],'北海市':[109.12,21.48],'钦州市':[108.62,21.95],'贵港市':[109.6,23.1], + '玉林市':[110.17,22.63],'百色市':[106.62,23.9],'贺州市':[111.55,24.42],'河池市':[108.07,24.7], + 'æµ·å£å¸‚':[110.32,20.03],'三亚市':[109.5,18.25],'五指山市':[109.52,18.78],'ç¼æµ·å¸‚':[110.47,19.25], + '儋州市':[109.57,19.52],'文昌市':[110.8,19.55],'万å®å¸‚':[110.4,18.8],'东方市':[108.63,19.1], + '定安县':[110.32,19.7],'屯昌县':[110.1,19.37],'澄迈县':[110.0,19.73],'临高县':[109.68,19.92], + '白沙黎æ—自治县':[109.45,19.23],'昌江黎æ—自治县':[109.05,19.25],'ä¹ä¸œé»Žæ—自治县':[109.17,18.75], + '陵水黎æ—自治县':[110.03,18.5],'ä¿äº­é»Žæ—è‹—æ—自治县':[109.7,18.63],'ç¼ä¸­é»Žæ—è‹—æ—自治县':[109.83,19.03], + 'æˆéƒ½å¸‚':[104.07,30.67],'自贡市':[104.78,29.35],'攀æžèб参':[101.72,26.58],'泸州市':[105.43,28.87], + '德阳市':[104.38,31.13],'绵阳市':[104.73,31.47],'广元市':[105.83,32.43],'é‚å®å¸‚':[105.57,30.52], + '内江市':[105.05,29.58],'ä¹å±±å¸‚':[103.77,29.57],'å—充市':[106.08,30.78],'眉山市':[103.83,30.05], + '宜宾市':[104.62,28.77],'广安市':[106.63,30.47],'达州市':[107.5,31.22],'雅安市':[103.0,29.98], + '巴中市':[106.77,31.85],'资阳市':[104.65,30.12],'阿åå·ž':[102.22,31.9],'甘孜州':[101.97,30.05], + '凉山州':[102.27,27.9],'贵阳市':[106.63,26.65],'六盘水市':[104.83,26.6],'éµä¹‰å¸‚':[106.92,27.73], + '安顺市':[105.95,26.25],'铜ä»å¸‚':[109.18,27.72],'毕节市':[105.28,27.3],'黔东州':[107.97,26.58], + 'é»”å—å·ž':[107.52,26.27],'昆明市':[102.72,25.05],'曲é–市':[103.8,25.5],'玉溪市':[102.55,24.35], + 'ä¿å±±å¸‚':[99.17,25.12],'昭通市':[103.72,27.33],'丽江市':[100.23,26.88],'临沧市':[100.08,23.88], + '楚雄州':[101.55,25.03],'红河州':[103.4,23.37],'文山州':[104.25,23.37],'西åŒå·ž':[100.8,22.02], + '大ç†å·ž':[100.23,25.6],'å¾·å®å·ž':[98.58,24.43],'怒江州':[98.85,25.85],'迪庆州':[99.7,27.83], + '拉è¨å¸‚':[91.13,29.65],'å±±å—地区':[91.77,29.23],'日喀则市':[88.88,29.27],'那曲地区':[92.07,31.48], + '阿里地区':[80.1,32.5],'西安市':[108.93,34.27],'铜å·å¸‚':[108.93,34.9],'å®é¸¡å¸‚':[107.13,34.37],'咸阳市':[108.7,34.33], + '渭å—市':[109.5,34.5],'延安市':[109.48,36.6],'汉中市':[107.02,33.07],'榆林市':[109.73,38.28], + '安康市':[109.02,32.68],'商洛市':[109.93,33.87],'兰州市':[103.82,36.07],'嘉峪关市':[98.27,39.8], + '金昌市':[102.18,38.5],'白银市':[104.18,36.55],'天水市':[105.72,34.58],'æ­¦å¨å¸‚':[102.63,37.93], + '张掖市':[100.45,38.93],'平凉市':[106.67,35.55],'酒泉市':[98.52,39.75],'庆阳市':[107.63,35.73], + '定西市':[104.62,35.58],'陇å—市':[104.92,33.4],'临å¤å·ž':[103.22,35.6],'甘å—å·ž':[102.92,34.98], + '西å®å¸‚':[101.78,36.62],'黄å—å·ž':[102.02,35.52],'æµ·å—å·ž':[100.62,36.28],'果洛州':[100.23,34.48], + '玉树州':[97.02,33.0],'海西州':[97.37,37.37],'北京市':[116.4,39.9],'天津市':[117.2,39.12], + '上海市':[121.47,31.23],'é‡åº†å¸‚':[106.55,29.57],'海北州':[100.9,36.97],'é“¶å·å¸‚':[106.28,38.47], + '石嘴山市':[106.38,39.02],'å´å¿ å¸‚':[106.2,37.98],'固原市':[106.28,36.0],'中å«å¸‚':[105.18,37.52], + 'ä¹Œé²æœ¨é½å¸‚':[87.62,43.82],'克拉玛ä¾å¸‚':[84.87,45.6],'åé²ç•ªå¸‚':[89.17,42.95],'哈密地区':[93.52,42.83], + '昌å‰å·ž':[87.3,44.02],'åšå°”塔拉州':[82.07,44.9],'巴音郭楞州':[86.15,41.77],'阿克è‹åœ°åŒº':[80.27,41.17], + '喀什地区':[75.98,39.47],'和田地区':[79.92,37.12],'伊çŠå·ž':[81.32,43.92],'塔城地区':[82.98,46.75],'阿勒泰地区':[88.13,47.85],'石河å­å¸‚':[86.03,44.3],'阿拉尔市':[81.28,40.55],'图木舒克市':[79.13,39.85],'五家渠市':[87.53,44.17]}; + + var convertData; + var convertedData; + + if(scope.panel.chart === 'china_map'){ + + myChart = echarts.init(document.getElementById(idd)); + + + + convertData = function (data) { + var res = []; + for (var i = 0; i < data.length; i++) { + var geoCoord = geoCoordMap[data[i].name]; + if (geoCoord) { + res.push({ + name: data[i].name, + value: geoCoord.concat(data[i].value) + }); + } + } + return res; +}; + +var option7 = { + + + tooltip: { + trigger: 'item', + formatter: function (params) { + return params.name + ' : ' + params.value[2]; + } + }, + + visualMap: { + min: 0, + max: radarmax, + calculable: true, + inRange: { + symbolSize: [5, 30], + color: ['#25f49f','#25f4d4','#25c5f4','#2585f4'], + }, + textStyle: { + color: '#aeb2b0' + } + }, + geo: { + map: 'china', + label: { + emphasis: { + show: false + } + }, + left:'3%', + right:'3%', + top:'3%', + bottom:'3%', + itemStyle: { + normal: { + areaColor: '#aeb2b0', + borderColor: '#F0FFFF' + }, + emphasis: { + areaColor: '#909292' + } + } + }, + series: [ + { + name: 'pm2.5', + type: 'scatter', + coordinateSystem: 'geo', + data: convertData(arrdata), + symbolSize: 12, + label: { + normal: { + show: false + }, + emphasis: { + show: false + } + }, + itemStyle: { + emphasis: { + borderColor: '#fff', + borderWidth: 1 + } + } + }, + { + name: 'Top 5', + type: 'effectScatter', + coordinateSystem: 'geo', + data: convertData(arrdata.sort(function (a, b) { + return b.value - a.value; + }).slice(0, 6)), + symbolSize: function (val) { + return val[2] / 10; + }, + showEffectOn: 'render', + rippleEffect: { + brushType: 'stroke' + }, + hoverAnimation: true, + label: { + normal: { + formatter: '{b}', + position: 'right', + show: true + } + }, + itemStyle: { + normal: { + color: '#f4e925', + shadowBlur: 10, + shadowColor: '#333' + } + }, + zlevel: 1 + } + ] +}; + + if(arrlabel.length===0){ + myChart.setOption(option_nodata);}else{ + myChart.setOption(option7); + } + + + } + + + if(scope.panel.chart === 'bmap'){ + + + myChart = echarts.init(document.getElementById(idd)); + + + + var baiducolor = [{ + 'featureType': 'water', + 'elementType': 'all', + 'stylers': { + 'color': '#000' + } + }, { + 'featureType': 'land', + 'elementType': 'all', + 'stylers': { + 'color': '#e1e1e0' + } + }, { + 'featureType': 'railway', + 'elementType': 'all', + 'stylers': { + 'visibility': 'off' + } + }, { + 'featureType': 'highway', + 'elementType': 'all', + 'stylers': { + 'color': '#fdfdfd' + } + }, { + 'featureType': 'highway', + 'elementType': 'labels', + 'stylers': { + 'visibility': 'off' + } + }, { + 'featureType': 'arterial', + 'elementType': 'geometry', + 'stylers': { + 'color': '#ffffff' + } + }, { + 'featureType': 'arterial', + 'elementType': 'geometry.fill', + 'stylers': { + 'color': '#ffffff' + } + }, { + 'featureType': 'poi', + 'elementType': 'all', + 'stylers': { + 'visibility': 'off' + } + }, { + 'featureType': 'green', + 'elementType': 'all', + 'stylers': { + 'visibility': 'off' + } + }, { + 'featureType': 'subway', + 'elementType': 'all', + 'stylers': { + 'visibility': 'off' + } + }, { + 'featureType': 'manmade', + 'elementType': 'all', + 'stylers': { + 'color': '#c2c2c2' + } + }, { + 'featureType': 'local', + 'elementType': 'all', + 'stylers': { + 'color': '#c2c2c2' + } + }, { + 'featureType': 'arterial', + 'elementType': 'labels', + 'stylers': { + 'visibility': 'off' + } + }, { + 'featureType': 'boundary', + 'elementType': 'all', + 'stylers': { + 'color': '#ffffff' + } + }, { + 'featureType': 'building', + 'elementType': 'all', + 'stylers': { + 'color': '#c2c2c2' + } + }, { + 'featureType': 'label', + 'elementType': 'labels.text.fill', + 'stylers': { + 'color': '#999999' + } + }]; + +if (dashboard.current.style === 'dark'){ + baiducolor = [{ + 'featureType': 'land', //调整土地颜色 + 'elementType': 'geometry', + 'stylers': { + 'color': '#081734' + } + }, { + 'featureType': 'building', //调整建筑物颜色 + 'elementType': 'geometry', + 'stylers': { + 'color': '#04406F' + } + }, { + 'featureType': 'building', //调整建筑物标签是å¦å¯è§† + 'elementType': 'labels', + 'stylers': { + 'visibility': 'off' + } + }, { + 'featureType': 'highway', //调整高速é“路颜色 + 'elementType': 'geometry', + 'stylers': { + 'color': '#050a15' + } + }, { + 'featureType': 'highway', //调整高速å字是å¦å¯è§† + 'elementType': 'labels', + 'stylers': { + 'visibility': 'off' + } + }, { + 'featureType': 'arterial', //调整一些干é“颜色 + 'elementType': 'geometry', + 'stylers': { + 'color': '#003051' + } + }, { + 'featureType': 'arterial', + 'elementType': 'labels', + 'stylers': { + 'visibility': 'off' + } + }, { + 'featureType': 'green', + 'elementType': 'geometry', + 'stylers': { + 'visibility': 'off' + } + }, { + 'featureType': 'water', + 'elementType': 'geometry', + 'stylers': { + 'color': '#044161' + } + }, { + 'featureType': 'subway', //调整地é“颜色 + 'elementType': 'geometry.stroke', + 'stylers': { + 'color': '#003051' + } + }, { + 'featureType': 'subway', + 'elementType': 'labels', + 'stylers': { + 'visibility': 'off' + } + }, { + 'featureType': 'railway', + 'elementType': 'geometry', + 'stylers': { + 'visibility': 'off' + } + }, { + 'featureType': 'railway', + 'elementType': 'labels', + 'stylers': { + 'visibility': 'off' + } + }, { + 'featureType': 'all', //调整所有的标签的边缘颜色 + 'elementType': 'labels.text.stroke', + 'stylers': { + 'color': '#313131' + } + }, { + 'featureType': 'all', //调整所有标签的填充颜色 + 'elementType': 'labels.text.fill', + 'stylers': { + 'color': '#FFFFFF' + } + }, { + 'featureType': 'manmade', + 'elementType': 'geometry', + 'stylers': { + 'visibility': 'off' + } + }, { + 'featureType': 'manmade', + 'elementType': 'labels', + 'stylers': { + 'visibility': 'off' + } + }, { + 'featureType': 'local', + 'elementType': 'geometry', + 'stylers': { + 'visibility': 'off' + } + }, { + 'featureType': 'local', + 'elementType': 'labels', + 'stylers': { + 'visibility': 'off' + } + }, { + 'featureType': 'subway', + 'elementType': 'geometry', + 'stylers': { + 'lightness': -65 + } + }, { + 'featureType': 'railway', + 'elementType': 'all', + 'stylers': { + 'lightness': -40 + } + }, { + 'featureType': 'boundary', + 'elementType': 'geometry', + 'stylers': { + 'color': '#8b8787', + 'weight': '1', + 'lightness': -29 + } + }]; + +} + + convertData = function (data) { + var res = []; + for (var i = 0; i < data.length; i++) { + var geoCoord = geoCoordMap[data[i].name]; + if (geoCoord) { + res.push({ + name: data[i].name, + value: geoCoord.concat(data[i].value) + }); + } + } + return res; +}; + + + +var option8 = { + + tooltip : { + trigger: 'item' + }, + visualMap: { + min: 0, + max: radarmax, + calculable: false, + inRange: { + symbolSize: [10, 30], + color: ['#4defe0','#4dd4ef','#4daeef','#4d8eef'], + }, + textStyle: { + color: '#aeb2b0' + } + }, + bmap: { + center: [104.114129, 37.550339], + zoom: 5, + roam: true, + mapStyle: { + styleJson: baiducolor + } + }, + series : [ + { + + type: 'scatter', + coordinateSystem: 'bmap', + data: convertData(arrdata), + symbolSize: function (val) { + return val[2] / 10; + }, + label: { + normal: { + formatter: '{b}', + position: 'right', + show: false + }, + emphasis: { + show: true + } + }, + itemStyle: { + normal: { + color: 'purple' + } + } + }, + { + name: 'Top 5', + type: 'effectScatter', + coordinateSystem: 'bmap', + data: convertData(arrdata.sort(function (a, b) { + return b.value - a.value; + }).slice(0, 5)), + symbolSize: function (val) { + return val[2] / 10; + }, + showEffectOn: 'render', + rippleEffect: { + brushType: 'stroke' + }, + hoverAnimation: true, + label: { + normal: { + formatter: '{b}', + position: 'right', + show: true + } + }, + itemStyle: { + normal: { + color: 'purple', + shadowBlur: 10, + shadowColor: '#333' + } + }, + zlevel: 1 + } + ] +}; + if(arrlabel.length===0){ + myChart.setOption(option_nodata);}else{ + myChart.setOption(option8); + } + + } + + + if(scope.panel.chart === 'cmap'){ + + myChart= echarts.init(document.getElementById(idd)); + + + var data = arrdata; + convertData = function (data) { + var res = []; + for (var i = 0; i < data.length; i++) { + var geoCoord = geoCoordMap[data[i].name]; + if (geoCoord) { + res.push({ + name: data[i].name, + value: geoCoord.concat(data[i].value) + }); + } + } + return res; + }; + + convertedData = [ + convertData(data), + convertData(data.sort(function (a, b) { + return b.value - a.value; + }).slice(0, 6)) + ]; + + + var option = { + backgroundColor: labelcolor?'#404a59':'rgba(91, 192, 222, 0.0)', + animation: true, + animationDuration: 1000, + animationEasing: 'cubicInOut', + animationDurationUpdate: 1000, + animationEasingUpdate: 'cubicInOut', + title: [ + + { + id: 'statistic', + right: 120, + top: 40, + width: 100, + textStyle: { + color: labelcolor?'#fff':'#363636', + fontSize: 20 + } + } + ], + toolbox: { + iconStyle: { + normal: { + borderColor: labelcolor?'#fff':'#9aa3b7' + }, + emphasis: { + borderColor: labelcolor?'#b1e4ff':'#102b37' + } + } + }, + brush: { + outOfBrush: { + color: labelcolor?'#abc':'#ddedfe' + }, + brushStyle: { + borderWidth: 2, + color: 'rgba(0,0,0,0.2)', + borderColor: 'rgba(0,0,0,0.5)', + }, + seriesIndex: [0, 1], + throttleType: 'debounce', + throttleDelay: 300, + geoIndex: 0 + }, + geo: { + map: 'china', + left: '5%', + top: '5%', + bottom: '5%', + + label: { + emphasis: { + show: false + } + }, + roam: true, + itemStyle: { + normal: { + areaColor: labelcolor?'#323c48':'#9aa3b7', + borderColor: '#111' + }, + emphasis: { + areaColor: labelcolor?'#2a333d':'#91949c' + } + } + }, + tooltip : { + trigger: 'item' + }, + visualMap: { + show:false, + min: 0, + max: radarmax, + calculable: false, + inRange: { + symbolSize: [5, 15], + + + }, + textStyle: { + color: '#fff' + } + }, + + grid: { + right: '5%', + top: 100, + bottom: 40, + width: '30%' + }, + xAxis: { + type: 'value', + scale: true, + position: 'top', + boundaryGap: false, + splitLine: {show: false}, + axisLine: {show: false}, + axisTick: {show: false}, + axisLabel: {margin: 2, textStyle: {color: labelcolor?'#aaa':'#363636'}}, + }, + yAxis: { + type: 'category', + + nameGap: 16, + axisLine: {show: false, lineStyle: {color: '#ddd'}}, + axisTick: {show: false, lineStyle: {color: '#ddd'}}, + axisLabel: {interval: 0, textStyle: {color: labelcolor?'#ddd':'#363636'}}, + data: [] + }, + series : [ + { + + type: 'scatter', + coordinateSystem: 'geo', + data: convertedData[0], + symbolSize: function (val) { + return Math.max(val[2] / 10, 8); + }, + label: { + normal: { + formatter: '{b}', + position: 'right', + show: false + }, + emphasis: { + show: true + } + }, + itemStyle: { + normal: { + color: '#347fef' + } + } + }, + { + name: 'Top 5', + type: 'effectScatter', + coordinateSystem: 'geo', + data: convertedData[1], + symbolSize: function (val) { + return Math.max(val[2] / 10, 8); + }, + showEffectOn: 'render', + rippleEffect: { + brushType: 'stroke' + }, + hoverAnimation: true, + label: { + normal: { + formatter: '{b}', + position: 'right', + show: true + } + }, + itemStyle: { + normal: { + color: '#f4cf25', + shadowBlur: 10, + shadowColor: '#333' + } + }, + zlevel: 1 + }, + { + id: 'bar', + zlevel: 2, + type: 'bar', + symbol: 'none', + itemStyle: { + normal: { + color: '#347fef' + } + }, + data: [] + } + ] + }; + renderBrushed = function(params) { + var mainSeries = params.batch[0].selected[0]; + + var selectedItems = []; + var categoryData = []; + var barData = []; + var maxBar = 30; + var sum = 0; + var count = 0; + + for (var i = 0; i < mainSeries.dataIndex.length; i++) { + var rawIndex = mainSeries.dataIndex[i]; + var dataItem = convertedData[0][rawIndex]; + var pmValue = dataItem.value[2]; + + sum += pmValue; + count++; + + selectedItems.push(dataItem); + } + + selectedItems.sort(function (a, b) { + return a.value[2] - b.value[2]; + }); + + for (var i3 = 0; i3 < Math.min(selectedItems.length, maxBar); i3++) { + categoryData.push(selectedItems[i3].name); + barData.push(selectedItems[i3].value[2]); + } + + this.setOption({ + yAxis: { + data: categoryData + }, + xAxis: { + axisLabel: {show: !!count} + }, + title: { + id: 'statistic', + right:'15%', + text: count ? (scope.panel.isEN?'Average Click: ':'å¹³å‡ç‚¹å‡»é‡: ') + (sum / count).toFixed(0) : '' + }, + series: { + id: 'bar', + data: barData + } + }); + }; + + myChart.on('brushselected', renderBrushed); + + myChart.setOption(option); + + + setTimeout(function () { + myChart.dispatchAction({ + type: 'brush', + areas: [ + { + geoIndex: 0, + brushType: 'polygon', + coordRange: [[98.289152,39.77313],[123.97,47.33],[121.15,31.89],[102.52,24.35]] + } + ] + }); + }, 0); + + +} + + if(scope.panel.chart === 'zmap'){ + + myChart= echarts.init(document.getElementById(idd)); + var data11 = arrdata; + convertData = function (data) { + var res = []; + for (var i = 0; i < data.length; i++) { + var geoCoord = geoCoordMap[data[i].name]; + if (geoCoord) { + res.push({ + name: data[i].name, + value: geoCoord.concat(data[i].value) + }); + } + } + return res; + }; + + convertedData = [ + convertData(data11), + convertData(data11.sort(function (a, b) { + return b.value - a.value; + }).slice(0, 6)) + ]; + + + var option11 = { + backgroundColor: labelcolor?'#202328':'rgba(91, 192, 222, 0.0)', + animation: true, + animationDuration: 1000, + animationEasing: 'cubicInOut', + animationDurationUpdate: 1000, + animationEasingUpdate: 'cubicInOut', + title: [ + + { + id: 'statistic', + right: 120, + top: 40, + width: 100, + textStyle: { + color: labelcolor?'#fff':'#363636', + fontSize: 20 + } + } + ], + toolbox: { + iconStyle: { + normal: { + borderColor: labelcolor?'#fff':'#9aa3b7' + }, + emphasis: { + borderColor: labelcolor?'#b1e4ff':'#102b37' + } + } + }, + brush: { + outOfBrush: { + color: labelcolor?'#abc':'#ddedfe' + }, + brushStyle: { + borderWidth: 2, + color: 'rgba(0,0,0,0.2)', + borderColor: 'rgba(0,0,0,0.5)', + }, + seriesIndex: [0, 1], + throttleType: 'debounce', + throttleDelay: 300, + geoIndex: 0 + }, + geo: { + map: 'china', + left: '0%', + top: '18%', + right:'40%', + bottom: '18%', + + label: { + emphasis: { + show: false + } + }, + roam: true, + itemStyle: { + normal: { + areaColor: labelcolor?'#323c48':'#9aa3b7', + borderColor: labelcolor?'#202328':'#111', + borderWidth:1 + }, + emphasis: { + areaColor: labelcolor?'#2a333d':'#91949c' + } + } + }, + tooltip : { + trigger: 'item' + }, + visualMap: { + show:false, + min: 0, + max: radarmax, + calculable: false, + inRange: { + symbolSize: [5, 15], + + + }, + textStyle: { + color: '#fff' + } + }, + + grid: { + right: '5%', + top: 100, + bottom: 40, + width: '30%' + }, + xAxis: { + type: 'value', + scale: true, + position: 'top', + boundaryGap: false, + splitLine: {show: false}, + axisLine: {show: false}, + axisTick: {show: false}, + axisLabel: {margin: 2, textStyle: {color: labelcolor?'#aaa':'#363636'}}, + }, + yAxis: { + type: 'category', + + nameGap: 16, + axisLine: {show: false, lineStyle: {color: '#ddd'}}, + axisTick: {show: false, lineStyle: {color: '#ddd'}}, + axisLabel: {interval: 0, textStyle: {color: labelcolor?'#ddd':'#363636'}}, + data: [] + }, + series : [ + { + + type: 'scatter', + coordinateSystem: 'geo', + data: convertedData[0], + symbolSize: function (val) { + return Math.max(val[2] / 10, 8); + }, + label: { + normal: { + formatter: '{b}', + position: 'right', + show: false + }, + emphasis: { + show: true + } + }, + itemStyle: { + normal: { + color: '#f4cf25' + } + } + }, + { + name: 'Top 5', + type: 'effectScatter', + coordinateSystem: 'geo', + data: convertedData[1], + symbolSize: function (val) { + return Math.max(val[2] / 10, 8); + }, + showEffectOn: 'render', + rippleEffect: { + brushType: 'stroke' + }, + hoverAnimation: true, + label: { + normal: { + formatter: '{b}', + position: 'right', + show: true + } + }, + itemStyle: { + normal: { + color: '#f4cf25', + shadowBlur: 10, + shadowColor: '#333' + } + }, + zlevel: 1 + }, + { + id: 'bar', + zlevel: 2, + type: 'bar', + symbol: 'none', + itemStyle: { + normal: { + color: '#347fef' + } + }, + data: [] + } + ] + }; + + renderBrushed=function (params) { + var mainSeries = params.batch[0].selected[0]; + + var selectedItems = []; + var categoryData = []; + var barData = []; + var maxBar = 30; + var sum = 0; + var count = 0; + + for (var i = 0; i < mainSeries.dataIndex.length; i++) { + var rawIndex = mainSeries.dataIndex[i]; + var dataItem = convertedData[0][rawIndex]; + var pmValue = dataItem.value[2]; + + sum += pmValue; + count++; + + selectedItems.push(dataItem); + } + + selectedItems.sort(function (a, b) { + return a.value[2] - b.value[2]; + }); + + for (var i1 = 0; i1 < Math.min(selectedItems.length, maxBar); i1++) { + categoryData.push(selectedItems[i1].name); + barData.push(selectedItems[i1].value[2]); + } + + this.setOption({ + yAxis: { + data: categoryData + }, + xAxis: { + axisLabel: {show: !!count} + }, + title: { + id: 'statistic', + right:'15%', + text: count ? (scope.panel.isEN?'Average Click: ':'å¹³å‡ç‚¹å‡»é‡: ') + (sum / count).toFixed(0) : '' + }, + series: { + id: 'bar', + data: barData + } + }); + }; + + myChart.on('brushselected', renderBrushed); + + myChart.setOption(option11); + + + setTimeout(function () { + myChart.dispatchAction({ + type: 'brush', + areas: [ + { + geoIndex: 0, + brushType: 'polygon', + coordRange: [[98.289152,29.77313],[98.289152,47.33],[123.97,47.33],[123.97,29.77313]] + } + ] + }); + }, 0); + + + + } + + + // Populate legend + if(elem.is(":visible")){ + setTimeout(function(){ + // scope.legend = plot.getData(); + if(!scope.$$phase) { + scope.$apply(); + } + }); + } + + } catch(e) { + elem.text(e); + } + }); + } + + elem.bind("plotclick", function (event, pos, object) { + if(object) { + scope.build_search(scope.data[object.seriesIndex]); + scope.panel.lastColor = object.series.color; + } + }); + + var $tooltip = $('
'); + elem.bind("plothover", function (event, pos, item) { + if (item) { + var value = scope.panel.chart === 'bar' ? item.datapoint[1] : item.datapoint[1][0][1]; + // if (scope.panel.mode === 'count') { + // value = value.toFixed(0); + // } else { + // value = value.toFixed(scope.panel.decimal_points); + // } + $tooltip + .html( + kbn.query_color_dot(item.series.color, 20) + ' ' + + item.series.label + " (" + dashboard.numberWithCommas(value.toFixed(scope.panel.decimal_points)) +")" + ) + .place_tt(pos.pageX, pos.pageY); + } else { + $tooltip.remove(); + } + }); + + } + }; + }); + +}); diff --git a/src/app/panels/column/editor.html b/src/app/panels/column/editor.html old mode 100755 new mode 100644 index b85e5f96f..a45041691 --- a/src/app/panels/column/editor.html +++ b/src/app/panels/column/editor.html @@ -3,7 +3,7 @@

Add Panel to Column

Select Type -
+

@@ -13,13 +13,13 @@

Add Panel to Column

Panels

- - - - - - - + + + + + + + diff --git a/src/app/panels/column/module.html b/src/app/panels/column/module.html old mode 100755 new mode 100644 index 864ec84b3..ef306a2dd --- a/src/app/panels/column/module.html +++ b/src/app/panels/column/module.html @@ -1,16 +1,18 @@
- -
- -
-
- × - Oops! {{panel.error}} +
+ +
+ +
+
+ × + Oops! {{panel.error}} +
+
+ +
+
-
- -
-
-
\ No newline at end of file +
diff --git a/src/app/panels/column/module.js b/src/app/panels/column/module.js old mode 100755 new mode 100644 index 3c5a41610..05f292314 --- a/src/app/panels/column/module.js +++ b/src/app/panels/column/module.js @@ -1,105 +1,119 @@ /* - ## Column + ## Column - ### Parameters - * panels :: an array of panel objects. All of their spans should be set to 12 + ### Parameters + * panels :: an array of panel objects. All of their spans should be set to 12 -*/ + */ define([ - 'angular', - 'app', - 'underscore', - 'config' -], -function (angular, app, _, config) { - 'use strict'; - - var module = angular.module('kibana.panels.column', []); - - app.useModule(module); - - module.controller('column', function($scope, $rootScope, $timeout) { - $scope.panelMeta = { - status : "Stable", - description : "A pseudo panel that lets you add other panels to be arranged in a column with "+ + 'angular', + 'app', + 'underscore', + 'config' + ], + function (angular, app, _, config) { + 'use strict'; + + var module = angular.module('kibana.panels.column', []); + + app.useModule(module); + + module.controller('column', function($scope, $rootScope, $timeout) { + $scope.panelMeta = { + status : "Stable", + description : "A pseudo panel that lets you add other panels to be arranged in a column with "+ "defined heights." - }; - - // Set and populate defaults - var _d = { - panels : [] - }; - _.defaults($scope.panel,_d); - - $scope.init = function(){ - $scope.reset_panel(); - }; - - $scope.toggle_row = function(panel) { - panel.collapse = panel.collapse ? false : true; - if (!panel.collapse) { - $timeout(function() { - $scope.send_render(); - }); - } - }; - - $scope.send_render = function() { - $scope.$broadcast('render'); - }; - - $scope.add_panel = function(panel) { - $scope.panel.panels.push(panel); - }; - - $scope.reset_panel = function(type) { - $scope.new_panel = { - loading: false, - error: false, - sizeable: false, - span: 12, - height: "150px", - editable: true, - type: type, - draggable: false }; - }; - }); + // Set and populate defaults + var _d = { + display:'block', + icon:"icon-caret-down", + panels : [] + }; + _.defaults($scope.panel,_d); - module.directive('columnEdit', function($compile,$timeout) { - return { - scope : { - new_panel:"=panel", - row:"=", - config:"=", - dashboards:"=", - type:"=type" - }, - link: function(scope, elem) { - scope.$on('render', function () { - - // Make sure the digest has completed and populated the attributes + $scope.init = function(){ + $scope.reset_panel(); + }; + + $scope.toggle_row = function(panel) { + panel.collapse = panel.collapse ? false : true; + if (!panel.collapse) { $timeout(function() { - // Create a reference to the new_panel as panel so that the existing - // editors work with our isolate scope - scope.panel = scope.new_panel; - var template = '
'; - - if(!(_.isUndefined(scope.type)) && scope.type !== "") { - template = template+'
'; - } - elem.html($compile(angular.element(template))(scope)); + $scope.send_render(); }); - }); - } - }; - }); + } + }; + + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; - module.filter('withoutColumn', function() { - return function() { - return _.without(config.panel_names,'column'); - }; + $scope.send_render = function() { + $scope.$broadcast('render'); + }; + + $scope.add_panel = function(panel) { + $scope.panel.panels.push(panel); + }; + + $scope.reset_panel = function(type) { + $scope.new_panel = { + loading: false, + error: false, + sizeable: false, + span: 12, + height: "150px", + editable: true, + type: type, + draggable: false + }; + }; + + }); + + module.directive('columnEdit', function($compile,$timeout) { + return { + scope : { + new_panel:"=panel", + row:"=", + config:"=", + dashboards:"=", + type:"=type" + }, + link: function(scope, elem) { + scope.$on('render', function () { + + // Make sure the digest has completed and populated the attributes + $timeout(function() { + // Create a reference to the new_panel as panel so that the existing + // editors work with our isolate scope + scope.panel = scope.new_panel; + var template = '
'; + + if(!(_.isUndefined(scope.type)) && scope.type !== "") { + template = template+'
'; + } + elem.html($compile(angular.element(template))(scope)); + }); + }); + } + }; + }); + + module.filter('withoutColumn', function() { + return function() { + return _.without(config.panel_names,'column'); + }; + }); }); -}); \ No newline at end of file diff --git a/src/app/panels/column/panelgeneral.html b/src/app/panels/column/panelgeneral.html old mode 100755 new mode 100644 index b952c1e03..436f3c801 --- a/src/app/panels/column/panelgeneral.html +++ b/src/app/panels/column/panelgeneral.html @@ -1,11 +1,11 @@ -
-
- -
-
- -
-
- -
-
\ No newline at end of file +
+
+ +
+
+ +
+
+ +
+
diff --git a/src/app/panels/derivequeries/editor.html b/src/app/panels/derivequeries/editor.html old mode 100755 new mode 100644 index 9858498ce..4d01641bb --- a/src/app/panels/derivequeries/editor.html +++ b/src/app/panels/derivequeries/editor.html @@ -21,3 +21,10 @@
+
+
Linkage Effective
+
+ +
+ +
diff --git a/src/app/panels/derivequeries/module.html b/src/app/panels/derivequeries/module.html old mode 100755 new mode 100644 index 3546f40ba..8dcbfad4d --- a/src/app/panels/derivequeries/module.html +++ b/src/app/panels/derivequeries/module.html @@ -17,17 +17,19 @@ box-sizing: border-box; /* Opera/IE 8+ */ } +
-
+
-
-
\ No newline at end of file +
+ diff --git a/src/app/panels/derivequeries/module.js b/src/app/panels/derivequeries/module.js old mode 100755 new mode 100644 index e5fe91335..2d0da23ee --- a/src/app/panels/derivequeries/module.js +++ b/src/app/panels/derivequeries/module.js @@ -24,14 +24,7 @@ function (angular, app, _) { module.controller('derivequeries', function($scope, $rootScope, querySrv, fields, dashboard, filterSrv) { $scope.panelMeta = { - modals : [ - { - description: "Inspect", - icon: "icon-info-sign", - partial: "app/partials/inspector.html", - show: $scope.panel.spyable - } - ], + status : "Experimental", description : "Creates a new set of queries using the Elasticsearch terms facet. For example,"+ " you might want to create 5 queries showing the most frequent HTTP response codes. Be "+ @@ -48,8 +41,11 @@ function (angular, app, _) { field : '_type', fields : [], spyable : true, + linkage_id:'a', rest : false, size : 5, + display:'block', + icon:"icon-caret-down", mode : 'terms only', exclude : [], history : [], @@ -64,72 +60,85 @@ function (angular, app, _) { }; $scope.get_data = function() { - update_history($scope.panel.query); - - // Make sure we have everything for the request to complete - if(dashboard.indices.length === 0) { - return; - } + if(($scope.panel.linkage_id===dashboard.current.linkage_id)||dashboard.current.enable_linkage){ + update_history($scope.panel.query); - $scope.panelMeta.loading = true; - var request = $scope.ejs.Request().indices(dashboard.indices); - - // Terms mode - request = request - .facet($scope.ejs.TermsFacet('query') - .field($scope.panel.field) - .size($scope.panel.size) - .exclude($scope.panel.exclude) - .facetFilter($scope.ejs.QueryFilter( - $scope.ejs.FilteredQuery( - $scope.ejs.QueryStringQuery($scope.panel.query || '*'), - filterSrv.getBoolFilter(filterSrv.ids) - )))).size(0); - - $scope.populate_modal(request); - - var results = request.doSearch(); - - // Populate scope when we have results - results.then(function(results) { - $scope.panelMeta.loading = false; - var suffix; - if ($scope.panel.query === '' || $scope.panel.mode === 'terms only') { - suffix = ''; - } else if ($scope.panel.mode === 'AND') { - suffix = ' AND (' + $scope.panel.query + ')'; - } else if ($scope.panel.mode === 'OR') { - suffix = ' OR (' + $scope.panel.query + ')'; + // Make sure we have everything for the request to complete + if (dashboard.indices.length === 0) { + return; } - var ids = []; - var terms = results.facets.query.terms; - var others = []; - _.each(terms, function(v) { - var _q = $scope.panel.field+':"'+v.term+'"'+suffix; - // if it isn't in the list, remove it - var _iq = querySrv.findQuery(_q); - if(!_iq) { - ids.push(querySrv.set({alias: v.term, query:_q})); - } else { - ids.push(_iq.id); - } - others.push("NOT (" + _q + ")"); - }); - if ($scope.panel.rest) { - var _other_q = others.join(' AND '); - var _iq = querySrv.findQuery(_other_q); - if (!_iq) { - ids.push(querySrv.set({alias: 'other', query: _other_q})); - } else { - ids.push(_iq.id); - } - } - _.each(_.difference($scope.panel.ids,ids),function(id){ - querySrv.remove(id); + + $scope.display = function () { + if ($scope.panel.display === 'none') { + $scope.panel.display = 'block'; + $scope.panel.icon = "icon-caret-down"; + + + } else { + $scope.panel.display = 'none'; + $scope.panel.icon = "icon-caret-up"; + } + }; + $scope.panelMeta.loading = true; + var request = $scope.ejs.Request().indices(dashboard.indices); + + // Terms mode + request = request + .facet($scope.ejs.TermsFacet('query') + .field($scope.panel.field) + .size($scope.panel.size) + .exclude($scope.panel.exclude) + .facetFilter($scope.ejs.QueryFilter( + $scope.ejs.FilteredQuery( + $scope.ejs.QueryStringQuery($scope.panel.query || '*'), + filterSrv.getBoolFilter(filterSrv.ids) + )))).size(0); + + $scope.populate_modal(request); + + var results = request.doSearch(); + + // Populate scope when we have results + results.then(function (results) { + $scope.panelMeta.loading = false; + var suffix; + if ($scope.panel.query === '' || $scope.panel.mode === 'terms only') { + suffix = ''; + } else if ($scope.panel.mode === 'AND') { + suffix = ' AND (' + $scope.panel.query + ')'; + } else if ($scope.panel.mode === 'OR') { + suffix = ' OR (' + $scope.panel.query + ')'; + } + var ids = []; + var terms = results.facets.query.terms; + var others = []; + _.each(terms, function (v) { + var _q = $scope.panel.field + ':"' + v.term + '"' + suffix; + // if it isn't in the list, remove it + var _iq = querySrv.findQuery(_q); + if (!_iq) { + ids.push(querySrv.set({alias: v.term, query: _q})); + } else { + ids.push(_iq.id); + } + others.push("NOT (" + _q + ")"); + }); + if ($scope.panel.rest) { + var _other_q = others.join(' AND '); + var _iq = querySrv.findQuery(_other_q); + if (!_iq) { + ids.push(querySrv.set({alias: 'other', query: _other_q})); + } else { + ids.push(_iq.id); + } + } + _.each(_.difference($scope.panel.ids, ids), function (id) { + querySrv.remove(id); + }); + $scope.panel.ids = ids; + dashboard.refresh(); }); - $scope.panel.ids = ids; - dashboard.refresh(); - }); + } }; $scope.set_refresh = function (state) { @@ -158,4 +167,4 @@ function (angular, app, _) { } }; }); -}); \ No newline at end of file +}); diff --git a/src/app/panels/docviewer/editor.html b/src/app/panels/docviewer/editor.html index 978c4535c..f56793b15 100644 --- a/src/app/panels/docviewer/editor.html +++ b/src/app/panels/docviewer/editor.html @@ -29,4 +29,11 @@ + +
+
Linkage Effective
+
+ +
+
\ No newline at end of file diff --git a/src/app/panels/docviewer/module.html b/src/app/panels/docviewer/module.html index 30f0d424f..9f4b3694e 100644 --- a/src/app/panels/docviewer/module.html +++ b/src/app/panels/docviewer/module.html @@ -1,16 +1,17 @@
+
-
+
{{docIndex+1}} of {{data.length}} available for paging
-
+

No document found

-
+
- +

Title

@@ -19,7 +20,8 @@

Content

- +
-
\ No newline at end of file +
+
diff --git a/src/app/panels/docviewer/module.js b/src/app/panels/docviewer/module.js index 7db4d30c3..cdf5c0c6f 100644 --- a/src/app/panels/docviewer/module.js +++ b/src/app/panels/docviewer/module.js @@ -17,14 +17,7 @@ function (angular, app, kbn, _/*, $*/) { module.controller('docviewer', function($scope, dashboard, fields, querySrv, filterSrv, $http) { $scope.panelMeta = { - modals: [ - { - description: 'Inspect', - icon: 'icon-info-sign', - partial: 'app/partials/inspector.html', - show: $scope.panel.spyable - } - ], + editorTabs: [ { title: 'Queries', @@ -46,8 +39,11 @@ function (angular, app, kbn, _/*, $*/) { custom: '' }, titleField: '', + display:'block', + icon:"icon-caret-down", contentField: '', uniqueKey: 'id', + linkage_id:'a', max_rows: 20, fragsize: 0, simplePre: '', @@ -77,6 +73,18 @@ function (angular, app, kbn, _/*, $*/) { $scope.refresh = state; }; + $scope.display=function() { + if($scope.panel.display==='none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; + $scope.close_edit = function() { if ($scope.refresh) { $scope.get_data(); @@ -90,71 +98,73 @@ function (angular, app, kbn, _/*, $*/) { }; $scope.get_data = function() { - // Show the spinning wheel icon - $scope.panelMeta.loading = true; - - // Set Solr server - $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); - var request = $scope.sjs.Request(); - - // Construct Solr query - var fq = ''; - if (filterSrv.getSolrFq()) { - fq = '&' + filterSrv.getSolrFq(); - } - var wt = '&wt=json'; - var fl = '&fl=' + $scope.panel.titleField + ' ' + $scope.panel.contentField + ' ' + $scope.panel.uniqueKey; - var rows_limit = '&rows=' + $scope.panel.max_rows; - var hl = '&hl=true&hl.fl=' + $scope.panel.titleField + ' ' + $scope.panel.contentField; - hl += '&hl.fragsize=' + $scope.panel.fragsize; - hl += '&hl.simple.pre=' + $scope.panel.simplePre + '&hl.simple.post=' + $scope.panel.simplePost; - - $scope.panel.queries.query = querySrv.getQuery(0) + fq + fl + wt + rows_limit + hl; - - // Set the additional custom query - if ($scope.panel.queries.custom != null) { - request = request.setQuery($scope.panel.queries.query + $scope.panel.queries.custom); - } else { - request = request.setQuery($scope.panel.queries.query); - } - - // Execute the search and get results - var results = request.doSearch(); - - // Populate scope when we have results - results.then(function(results) { - // If there's no result, do nothing. - if (results.response.docs.length === 0) { - $scope.data = []; - $scope.docIndex = -1; // this will be addbed by one and shown on the panel as zero. - $scope.panel.docTitle = ''; - $scope.panel.docContent = ''; - - return false; + if(($scope.panel.linkage_id===dashboard.current.linkage_id)||dashboard.current.enable_linkage){ + // Show the spinning wheel icon + $scope.panelMeta.loading = true; + + // Set Solr server + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + var request = $scope.sjs.Request(); + + // Construct Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); } - - $scope.data = results.response.docs; - $scope.highlighting = results.highlighting; - $scope.docIndex = 0; - var uniquekey = $scope.data[$scope.docIndex][$scope.panel.uniqueKey]; - - if ($scope.highlighting[uniquekey][$scope.panel.titleField]) { - $scope.panel.docTitle = $scope.highlighting[uniquekey][$scope.panel.titleField]; - } else { - $scope.panel.docTitle = $scope.data[$scope.docIndex][$scope.panel.titleField]; - } - - if ($scope.highlighting[uniquekey][$scope.panel.contentField]) { - $scope.panel.docContent = $scope.highlighting[uniquekey][$scope.panel.contentField]; + var wt = '&wt=json'; + var fl = '&fl=' + $scope.panel.titleField + ' ' + $scope.panel.contentField + ' ' + $scope.panel.uniqueKey; + var rows_limit = '&rows=' + $scope.panel.max_rows; + var hl = '&hl=true&hl.fl=' + $scope.panel.titleField + ' ' + $scope.panel.contentField; + hl += '&hl.fragsize=' + $scope.panel.fragsize; + hl += '&hl.simple.pre=' + $scope.panel.simplePre + '&hl.simple.post=' + $scope.panel.simplePost; + + $scope.panel.queries.query = querySrv.getQuery(0) + fq + fl + wt + rows_limit + hl; + + // Set the additional custom query + if ($scope.panel.queries.custom != null) { + request = request.setQuery($scope.panel.queries.query + $scope.panel.queries.custom); } else { - $scope.panel.docContent = $scope.data[$scope.docIndex][$scope.panel.contentField]; + request = request.setQuery($scope.panel.queries.query); } - $scope.render(); - }); - - // Hide the spinning wheel icon - $scope.panelMeta.loading = false; + // Execute the search and get results + var results = request.doSearch(); + + // Populate scope when we have results + results.then(function (results) { + // If there's no result, do nothing. + if (results.response.docs.length === 0) { + $scope.data = []; + $scope.docIndex = -1; // this will be addbed by one and shown on the panel as zero. + $scope.panel.docTitle = ''; + $scope.panel.docContent = ''; + + return false; + } + + $scope.data = results.response.docs; + $scope.highlighting = results.highlighting; + $scope.docIndex = 0; + var uniquekey = $scope.data[$scope.docIndex][$scope.panel.uniqueKey]; + + if ($scope.highlighting[uniquekey][$scope.panel.titleField]) { + $scope.panel.docTitle = $scope.highlighting[uniquekey][$scope.panel.titleField]; + } else { + $scope.panel.docTitle = $scope.data[$scope.docIndex][$scope.panel.titleField]; + } + + if ($scope.highlighting[uniquekey][$scope.panel.contentField]) { + $scope.panel.docContent = $scope.highlighting[uniquekey][$scope.panel.contentField]; + } else { + $scope.panel.docContent = $scope.data[$scope.docIndex][$scope.panel.contentField]; + } + + $scope.render(); + }); + + // Hide the spinning wheel icon + $scope.panelMeta.loading = false; + } }; $scope.nextDoc = function() { diff --git a/src/app/panels/facet/editor.html b/src/app/panels/facet/editor.html old mode 100755 new mode 100644 index 58dcfd105..8c31c865e --- a/src/app/panels/facet/editor.html +++ b/src/app/panels/facet/editor.html @@ -30,3 +30,10 @@
Max Number of Facet Fields The maximum number of fields for faceting. W
+
+
Linkage Effective
+
+ +
+ +
diff --git a/src/app/panels/facet/module.html b/src/app/panels/facet/module.html old mode 100755 new mode 100644 index c0f3f5d06..d8f8b9ae7 --- a/src/app/panels/facet/module.html +++ b/src/app/panels/facet/module.html @@ -37,7 +37,7 @@ } -
+
{{panel.header_title}}
@@ -49,9 +49,9 @@
{{panel.header_title}}
diff --git a/src/app/panels/facet/module.js b/src/app/panels/facet/module.js old mode 100755 new mode 100644 index 3d30ff0ef..176fb2bd5 --- a/src/app/panels/facet/module.js +++ b/src/app/panels/facet/module.js @@ -24,12 +24,7 @@ define([ module.controller('facet', function($rootScope, $scope, fields, querySrv, dashboard, filterSrv) { $scope.panelMeta = { - modals: [{ - description: "Inspect", - icon: "icon-info-sign", - partial: "app/partials/inspector.html", - show: $scope.panel.spyable - }], + editorTabs: [{ title: 'Queries', src: 'app/partials/querySelect.html' @@ -42,6 +37,8 @@ define([ // Set and populate defaults var _d = { status: "Stable", + display:'block', + icon:"icon-caret-down", queries: { mode: 'all', ids: [], @@ -56,6 +53,7 @@ define([ overflow: 'min-height', fields: [], spyable: true, + linkage_id:'a', facet_limit: 10, maxnum_facets: 5, // Max number of facet fields that can be specified. // If we do too many facets on a really big data, we will run into Out Of Memory issue in JVM. @@ -89,6 +87,18 @@ define([ } }; + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; + $scope.remove_facet_field = function(field) { if (_.contains(fields.list, field) && _.indexOf($scope.panel.fields, field) > -1) { $scope.panel.fields = _.without($scope.panel.fields, field); @@ -106,131 +116,133 @@ define([ }; $scope.get_data = function(segment, query_id) { - $scope.panel.error = false; - delete $scope.panel.error; - // Make sure we have everything for the request to complete - if (dashboard.indices.length === 0) { - return; - } - $scope.panelMeta.loading = true; - $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); - - // What this segment is for? => to select which indices to query. - var _segment = _.isUndefined(segment) ? 0 : segment; - $scope.segment = _segment; - - $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + if(($scope.panel.linkage_id === dashboard.current.linkage_id)||dashboard.current.enable_linkage){ + $scope.panel.error = false; + delete $scope.panel.error; + // Make sure we have everything for the request to complete + if (dashboard.indices.length === 0) { + return; + } + $scope.panelMeta.loading = true; + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); - var request = $scope.sjs.Request().indices(dashboard.indices[_segment]); - var boolQuery = $scope.sjs.BoolQuery(); - _.each($scope.panel.queries.ids, function(id) { - boolQuery = boolQuery.should(querySrv.getEjsObj(id)); - }); + // What this segment is for? => to select which indices to query. + var _segment = _.isUndefined(segment) ? 0 : segment; + $scope.segment = _segment; - request = request.query( - $scope.sjs.FilteredQuery( - boolQuery, - filterSrv.getBoolFilter(filterSrv.ids) // search time range is provided here. - )).size($scope.panel.size * $scope.panel.pages); // Set the size of query result + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); - $scope.panel_request = request; + var request = $scope.sjs.Request().indices(dashboard.indices[_segment]); + var boolQuery = $scope.sjs.BoolQuery(); + _.each($scope.panel.queries.ids, function (id) { + boolQuery = boolQuery.should(querySrv.getEjsObj(id)); + }); - var fq = ''; - if (filterSrv.getSolrFq()) { - fq = '&' + filterSrv.getSolrFq(); - } + request = request.query( + $scope.sjs.FilteredQuery( + boolQuery, + filterSrv.getBoolFilter(filterSrv.ids) // search time range is provided here. + )).size($scope.panel.size * $scope.panel.pages); // Set the size of query result - var wt_json = '&wt=json'; - var facet = '&facet=true'; - var facet_fields = ''; + $scope.panel_request = request; - for (var i = 0; i < $scope.panel.fields.length; i++) { - facet_fields += '&facet.field=' + $scope.panel.fields[i]; - } - - // Set the panel's query - $scope.panel.queries.basic_query = querySrv.getORquery() + fq + facet + facet_fields; - $scope.panel.queries.query = $scope.panel.queries.basic_query + wt_json; + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + } - // Set the additional custom query - if ($scope.panel.queries.custom != null) { - request = request.setQuery($scope.panel.queries.query + $scope.panel.queries.custom); - } else { - request = request.setQuery($scope.panel.queries.query); - } + var wt_json = '&wt=json'; + var facet = '&facet=true'; + var facet_fields = ''; - var results = request.doSearch(); + for (var i = 0; i < $scope.panel.fields.length; i++) { + facet_fields += '&facet.field=' + $scope.panel.fields[i]; + } - // Populate scope when we have results - results.then(function(results) { - $scope.panelMeta.loading = false; - $scope.panel.offset = 0; + // Set the panel's query + $scope.panel.queries.basic_query = querySrv.getORquery() + fq + facet + facet_fields; + $scope.panel.queries.query = $scope.panel.queries.basic_query + wt_json; - if (_segment === 0) { - $scope.hits = 0; - $scope.data = []; - query_id = $scope.query_id = new Date().getTime(); + // Set the additional custom query + if ($scope.panel.queries.custom != null) { + request = request.setQuery($scope.panel.queries.query + $scope.panel.queries.custom); } else { - // Fix BUG with wrong total event count. - $scope.data = []; + request = request.setQuery($scope.panel.queries.query); } - // Check for error and abort if found - if (!(_.isUndefined(results.error))) { - $scope.panel.error = $scope.parse_error(results.error.msg); // There's also results.error.code - return; - } + var results = request.doSearch(); - // Check that we're still on the same query, if not stop - if ($scope.query_id === query_id) { - $scope.data = $scope.data.concat(_.map(results.response.docs, function(hit) { - var _h = _.clone(hit); - _h.kibana = { - _source: kbn.flatten_json(hit), - highlight: kbn.flatten_json(hit.highlighting || {}) - }; - - return _h; - })); - - // Solr does not need to accumulate hits count because it can get total count - // from a single faceted query. - $scope.hits = results.response.numFound; - $scope.panel.foundResults = $scope.hits === 0 ? false : true; - if (results.highlighting) { - $scope.highlighting = results.highlighting; - $scope.highlightingKeys = Object.keys(results.highlighting); - if ($.isEmptyObject($scope.highlighting[$scope.highlightingKeys[0]])) { // jshint ignore:line - $scope.highlight_flag = false; + // Populate scope when we have results + results.then(function (results) { + $scope.panelMeta.loading = false; + $scope.panel.offset = 0; + + if (_segment === 0) { + $scope.hits = 0; + $scope.data = []; + query_id = $scope.query_id = new Date().getTime(); } else { - $scope.highlight_flag = true; + // Fix BUG with wrong total event count. + $scope.data = []; } - } - var facet_results = results.facet_counts.facet_fields; - var facet_data = {}; - _.each($scope.panel.fields, function(field) { - facet_data[field] = []; - for (var i = 0; i < facet_results[field].length; i += 2) { - facet_data[field].push({ - value: facet_results[field][i], - count: facet_results[field][i + 1] - }); + + // Check for error and abort if found + if (!(_.isUndefined(results.error))) { + $scope.panel.error = $scope.parse_error(results.error.msg); // There's also results.error.code + return; } - }); - $scope.facet_data = facet_data; - } else { - return; - } - // If we're not sorting in reverse chrono order, query every index for - // size*pages results - // Otherwise, only get size*pages results then stop querying - if ($scope.panel.sortable && ($scope.data.length < $scope.panel.size * $scope.panel.pages || !((_.contains(filterSrv.timeField(), $scope.panel.sort[0])) && $scope.panel.sort[1] === 'desc')) && - _segment + 1 < dashboard.indices.length) { - $scope.get_data(_segment + 1, $scope.query_id); - } + // Check that we're still on the same query, if not stop + if ($scope.query_id === query_id) { + $scope.data = $scope.data.concat(_.map(results.response.docs, function (hit) { + var _h = _.clone(hit); + _h.kibana = { + _source: kbn.flatten_json(hit), + highlight: kbn.flatten_json(hit.highlighting || {}) + }; + + return _h; + })); + + // Solr does not need to accumulate hits count because it can get total count + // from a single faceted query. + $scope.hits = results.response.numFound; + $scope.panel.foundResults = $scope.hits === 0 ? false : true; + if (results.highlighting) { + $scope.highlighting = results.highlighting; + $scope.highlightingKeys = Object.keys(results.highlighting); + if ($.isEmptyObject($scope.highlighting[$scope.highlightingKeys[0]])) { // jshint ignore:line + $scope.highlight_flag = false; + } else { + $scope.highlight_flag = true; + } + } + var facet_results = results.facet_counts.facet_fields; + var facet_data = {}; + _.each($scope.panel.fields, function (field) { + facet_data[field] = []; + for (var i = 0; i < facet_results[field].length; i += 2) { + facet_data[field].push({ + value: facet_results[field][i], + count: facet_results[field][i + 1] + }); + } + }); + $scope.facet_data = facet_data; + } else { + return; + } - }); + // If we're not sorting in reverse chrono order, query every index for + // size*pages results + // Otherwise, only get size*pages results then stop querying + if ($scope.panel.sortable && ($scope.data.length < $scope.panel.size * $scope.panel.pages || !((_.contains(filterSrv.timeField(), $scope.panel.sort[0])) && $scope.panel.sort[1] === 'desc')) && + _segment + 1 < dashboard.indices.length) { + $scope.get_data(_segment + 1, $scope.query_id); + } + + }); + } }; $scope.populate_modal = function(request) { diff --git a/src/app/panels/filtering/editor.html b/src/app/panels/filtering/editor.html old mode 100755 new mode 100644 diff --git a/src/app/panels/filtering/meta.html b/src/app/panels/filtering/meta.html old mode 100755 new mode 100644 diff --git a/src/app/panels/filtering/module.html b/src/app/panels/filtering/module.html old mode 100755 new mode 100644 index 87bc77806..173d44715 --- a/src/app/panels/filtering/module.html +++ b/src/app/panels/filtering/module.html @@ -46,36 +46,34 @@ } -
-
No filters available
+
+
No filters available
{{filterSrv.list[id].type}} - {{filterSrv.list[id].mandate}} + {{filterSrv.list[id].mandate}} - + +
-
    -
  • {{key}} : {{ decodeFilterValue(value) | truncate }}
  • +
  • {{key}} : {{value | truncate}}
- - -
+
    -
  • {{key}} :
  • +
  • {{key}} :
-
+
diff --git a/src/app/panels/filtering/module.js b/src/app/panels/filtering/module.js old mode 100755 new mode 100644 index 9a8664cca..38d3c2936 --- a/src/app/panels/filtering/module.js +++ b/src/app/panels/filtering/module.js @@ -17,18 +17,15 @@ function (angular, app, _) { module.controller('filtering', function($scope, filterSrv, $rootScope, $location, dashboard) { $scope.panelMeta = { - modals: [{ - description: "Inspect", - icon: "icon-info-sign", - partial: "app/partials/inspector.html", - show: true - }], + status: "Stable", description: "A controllable list of all filters currently applied to the dashboard. You need one of these on your dashboard somewhere in order for all the panels to work properly while you are interacting with your data." }; // Set and populate defaults var _d = { + display:'block', + icon:"icon-caret-down", spyable: true }; _.defaults($scope.panel,_d); @@ -61,6 +58,18 @@ function (angular, app, _) { dashboard.refresh(); }; + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; + $scope.add = function(query) { query = query || '*'; filterSrv.set({ @@ -96,14 +105,6 @@ function (angular, app, _) { return true; } }; - - $scope.decodeFilterValue = function(value) { - if (value instanceof Date) { - return value.toLocaleDateString() + ' ' + value.toTimeString().substring(0,17); // e.g. 4/7/2017 11:45:34 GMT+0700 - } else { - return decodeURIComponent(value); - } - }; }); module.filter('truncate', function() { diff --git a/src/app/panels/fullTextSearch/editor.html b/src/app/panels/fullTextSearch/editor.html old mode 100755 new mode 100644 index c72558832..776e95bd7 --- a/src/app/panels/fullTextSearch/editor.html +++ b/src/app/panels/fullTextSearch/editor.html @@ -25,10 +25,10 @@
Header
Sorting
-
+
Sort
- - + +
@@ -71,3 +71,11 @@
Facet Limit
+
+
Linkage Effective
+
+ +
+ +
+ diff --git a/src/app/panels/fullTextSearch/micropanel.html b/src/app/panels/fullTextSearch/micropanel.html old mode 100755 new mode 100644 diff --git a/src/app/panels/fullTextSearch/module.html b/src/app/panels/fullTextSearch/module.html old mode 100755 new mode 100644 index 351ee47b7..607f1f1aa --- a/src/app/panels/fullTextSearch/module.html +++ b/src/app/panels/fullTextSearch/module.html @@ -37,13 +37,14 @@ } -
+
+
-
-
+
+
TitleTypeHeightDeleteMoveHideTitleTypeHeightDeleteMoveHide
{{app.title}}
- + @@ -96,14 +97,14 @@
Limit Your Search {{event.kibana._source[panel.header_field] | tableTruncate:panel.trimFactor:1}}
-
-
+
+

- + - + - + @@ -87,8 +87,7 @@
Fields - -
+
View: @@ -136,10 +137,10 @@
Limit Your Search +
- - + +
{{panel.offset+1}} to @@ -147,9 +148,10 @@
Limit Your Search - +
+ diff --git a/src/app/panels/fullTextSearch/module.js b/src/app/panels/fullTextSearch/module.js old mode 100755 new mode 100644 index 8fcf8145a..c9b54cb1d --- a/src/app/panels/fullTextSearch/module.js +++ b/src/app/panels/fullTextSearch/module.js @@ -34,12 +34,7 @@ define([ //app.useModule('ui.bootstrap') module.controller('fullTextSearch', function($rootScope, $scope, fields, querySrv, dashboard, filterSrv) { $scope.panelMeta = { - modals: [{ - description: "Inspect", - icon: "icon-info-sign", - partial: "app/partials/inspector.html", - show: $scope.panel.spyable - }], + editorTabs: [{ title: 'Paging', src: 'app/panels/table/pagination.html' @@ -54,6 +49,8 @@ define([ // Set and populate defaults var _d = { + display:'block', + icon:"icon-caret-down", status: "Stable", queries: { mode: 'all', @@ -84,6 +81,7 @@ define([ exportSize: 100, exportAll: true, facet_limit: 10, + linkage_id:'a', foundResults: true, show_queries:true, }; @@ -106,6 +104,18 @@ define([ $scope.percent = kbn.to_percent; + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; + $scope.toggle_micropanel = function(field, groups) { var docs = _.map($scope.data, function(_d) { return _d.kibana._source; @@ -170,29 +180,33 @@ define([ }; $scope.build_search = function(field, value, negate) { - var query; - // This needs to be abstracted somewhere - if (_.isArray(value)) { - // TODO: I don't think Solr has "AND" operator in query. - query = "(" + _.map(value, function(v) { - return angular.toJson(v); - }).join(" AND ") + ")"; - } else if (_.isUndefined(value)) { - query = '*:*'; - negate = !negate; - } else { - query = angular.toJson(value); - } - // TODO: Need to take a look here, not sure if need change. - filterSrv.set({ - type: 'field', - field: field, - query: query, - mandate: (negate ? 'mustNot' : 'must') - }); - $scope.panel.offset = 0; - dashboard.refresh(); + var query; + // This needs to be abstracted somewhere + if (_.isArray(value)) { + // TODO: I don't think Solr has "AND" operator in query. + query = "(" + _.map(value, function (v) { + return angular.toJson(v); + }).join(" AND ") + ")"; + } else if (_.isUndefined(value)) { + query = '*:*'; + negate = !negate; + } else { + query = angular.toJson(value); + } + // TODO: Need to take a look here, not sure if need change. + filterSrv.set({ + type: 'field', + field: field, + query: query, + mandate: (negate ? 'mustNot' : 'must') + }); + + $scope.panel.offset = 0; + dashboard.current.linkage_id = $scope.panel.linkage_id; + dashboard.current.enable_linkage=false; + dashboard.refresh(); + }; $scope.facet_label = function(key) { @@ -211,165 +225,167 @@ define([ }; $scope.get_data = function(segment, query_id) { - $scope.panel.error = false; - delete $scope.panel.error; - - // Make sure we have everything for the request to complete - if (dashboard.indices.length === 0) { - return; - } - $scope.panelMeta.loading = true; - $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); - - // What this segment is for? => to select which indices to query. - var _segment = _.isUndefined(segment) ? 0 : segment; - $scope.segment = _segment; - - $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); - - var request = $scope.sjs.Request().indices(dashboard.indices[_segment]); - var boolQuery = $scope.sjs.BoolQuery(); - _.each($scope.panel.queries.ids, function(id) { - boolQuery = boolQuery.should(querySrv.getEjsObj(id)); - }); - - request = request.query( - $scope.sjs.FilteredQuery( - boolQuery, - filterSrv.getBoolFilter(filterSrv.ids) // search time range is provided here. - )) - .highlight( - $scope.sjs.Highlight($scope.panel.highlight) - .fragmentSize(2147483647) // Max size of a 32bit unsigned int - .preTags('@start-highlight@') - .postTags('@end-highlight@') - ).size($scope.panel.size * $scope.panel.pages); // Set the size of query result - - $scope.panel_request = request; - - var fq = ''; - if (filterSrv.getSolrFq()) { - fq = '&' + filterSrv.getSolrFq(); - } - var query_size = $scope.panel.size * $scope.panel.pages; - var wt_json = '&wt=json'; - var facet = '&facet=true'; - var facet_fields = ''; - for (var i = 0; i < $scope.panel.fields.length; i++) { - facet_fields += '&facet.field=' + $scope.panel.fields[i]; - } - var rows_limit; - var sorting = ''; - - if ($scope.panel.sortable && $scope.panel.sort && $scope.panel.sort[0] !== undefined && $scope.panel.sort[1] !== undefined) { - sorting = '&sort=' + $scope.panel.sort[0] + ' ' + $scope.panel.sort[1]; - } - - // set the size of query result - if (query_size !== undefined && query_size !== 0) { - rows_limit = '&rows=' + query_size; - } else { // default - rows_limit = '&rows=25'; - } + if(($scope.panel.linkage_id === dashboard.current.linkage_id)||dashboard.current.enable_linkage){ + $scope.panel.error = false; + delete $scope.panel.error; - //set highlight part in sole query - var highlight; - if ($scope.panel.body_field) { - highlight = '&hl=true&hl.fl=' + $scope.panel.body_field; - } else { - highlight = ""; - } + // Make sure we have everything for the request to complete + if (dashboard.indices.length === 0) { + return; + } + $scope.panelMeta.loading = true; + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + + // What this segment is for? => to select which indices to query. + var _segment = _.isUndefined(segment) ? 0 : segment; + $scope.segment = _segment; + + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + var request = $scope.sjs.Request().indices(dashboard.indices[_segment]); + var boolQuery = $scope.sjs.BoolQuery(); + _.each($scope.panel.queries.ids, function (id) { + boolQuery = boolQuery.should(querySrv.getEjsObj(id)); + }); + + request = request.query( + $scope.sjs.FilteredQuery( + boolQuery, + filterSrv.getBoolFilter(filterSrv.ids) // search time range is provided here. + )) + .highlight( + $scope.sjs.Highlight($scope.panel.highlight) + .fragmentSize(2147483647) // Max size of a 32bit unsigned int + .preTags('@start-highlight@') + .postTags('@end-highlight@') + ).size($scope.panel.size * $scope.panel.pages); // Set the size of query result + + $scope.panel_request = request; + + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + } + var query_size = $scope.panel.size * $scope.panel.pages; + var wt_json = '&wt=json'; + var facet = '&facet=true'; + var facet_fields = ''; + for (var i = 0; i < $scope.panel.fields.length; i++) { + facet_fields += '&facet.field=' + $scope.panel.fields[i]; + } + var rows_limit; + var sorting = ''; + if ($scope.panel.sortable && $scope.panel.sort && $scope.panel.sort[0] !== undefined && $scope.panel.sort[1] !== undefined) { + sorting = '&sort=' + $scope.panel.sort[0] + ' ' + $scope.panel.sort[1]; + } - // Set the panel's query + // set the size of query result + if (query_size !== undefined && query_size !== 0) { + rows_limit = '&rows=' + query_size; + } else { // default + rows_limit = '&rows=25'; + } - //var query = $scope.panel.searchQuery == null ? querySrv.getQuery(0) : 'q=' + $scope.panel.searchQuery - $scope.panel.queries.basic_query = querySrv.getORquery() + fq + facet + facet_fields + sorting; - $scope.panel.queries.query = $scope.panel.queries.basic_query + wt_json + rows_limit + highlight; + //set highlight part in sole query + var highlight; + if ($scope.panel.body_field) { + highlight = '&hl=true&hl.fl=' + $scope.panel.body_field; + } else { + highlight = ""; + } - // Set the additional custom query - if ($scope.panel.queries.custom != null) { - request = request.setQuery($scope.panel.queries.query + $scope.panel.queries.custom); - } else { - request = request.setQuery($scope.panel.queries.query); - } - var results = request.doSearch(); + // Set the panel's query - // Populate scope when we have results - results.then(function(results) { - $scope.panelMeta.loading = false; - $scope.panel.offset = 0; + //var query = $scope.panel.searchQuery == null ? querySrv.getQuery(0) : 'q=' + $scope.panel.searchQuery + $scope.panel.queries.basic_query = querySrv.getORquery() + fq + facet + facet_fields + sorting; + $scope.panel.queries.query = $scope.panel.queries.basic_query + wt_json + rows_limit + highlight; - if (_segment === 0) { - $scope.hits = 0; - $scope.data = []; - query_id = $scope.query_id = new Date().getTime(); + // Set the additional custom query + if ($scope.panel.queries.custom != null) { + request = request.setQuery($scope.panel.queries.query + $scope.panel.queries.custom); } else { - // Fix BUG with wrong total event count. - $scope.data = []; + request = request.setQuery($scope.panel.queries.query); } - // Check for error and abort if found - if (!(_.isUndefined(results.error))) { - $scope.panel.error = $scope.parse_error(results.error.msg); // There's also results.error.code - return; - } + var results = request.doSearch(); + + // Populate scope when we have results + results.then(function (results) { + $scope.panelMeta.loading = false; + $scope.panel.offset = 0; - // Check that we're still on the same query, if not stop - if ($scope.query_id === query_id) { - $scope.data = $scope.data.concat(_.map(results.response.docs, function(hit) { - var _h = _.clone(hit); - _h.kibana = { - _source: kbn.flatten_json(hit), - highlight: kbn.flatten_json(hit.highlighting || {}) - }; - - return _h; - })); - - // Solr does not need to accumulate hits count because it can get total count - // from a single faceted query. - $scope.hits = results.response.numFound; - $scope.panel.foundResults = $scope.hits === 0 ? false : true; - if (results.highlighting) { - $scope.highlighting = results.highlighting; - $scope.highlightingKeys = Object.keys(results.highlighting); - - if ($.isEmptyObject($scope.highlighting[$scope.highlightingKeys[0]])) { // jshint ignore:line - $scope.highlight_flag = false; + if (_segment === 0) { + $scope.hits = 0; + $scope.data = []; + query_id = $scope.query_id = new Date().getTime(); } else { - $scope.highlight_flag = true; + // Fix BUG with wrong total event count. + $scope.data = []; } - } - var facet_results = results.facet_counts.facet_fields; - var facet_data = {}; - _.each($scope.panel.fields, function(field) { - facet_data[field] = []; - for (var i = 0; i < facet_results[field].length; i += 2) { - facet_data[field].push({ - value: facet_results[field][i], - count: facet_results[field][i + 1] - }); + + // Check for error and abort if found + if (!(_.isUndefined(results.error))) { + $scope.panel.error = $scope.parse_error(results.error.msg); // There's also results.error.code + return; } - }); - $scope.facet_data = facet_data; - // Keep only what we need for the set - $scope.data = $scope.data.slice(0, $scope.panel.size * $scope.panel.pages); - } else { - return; - } + // Check that we're still on the same query, if not stop + if ($scope.query_id === query_id) { + $scope.data = $scope.data.concat(_.map(results.response.docs, function (hit) { + var _h = _.clone(hit); + _h.kibana = { + _source: kbn.flatten_json(hit), + highlight: kbn.flatten_json(hit.highlighting || {}) + }; + + return _h; + })); + + // Solr does not need to accumulate hits count because it can get total count + // from a single faceted query. + $scope.hits = results.response.numFound; + $scope.panel.foundResults = $scope.hits === 0 ? false : true; + if (results.highlighting) { + $scope.highlighting = results.highlighting; + $scope.highlightingKeys = Object.keys(results.highlighting); + + if ($.isEmptyObject($scope.highlighting[$scope.highlightingKeys[0]])) { // jshint ignore:line + $scope.highlight_flag = false; + } else { + $scope.highlight_flag = true; + } + } + var facet_results = results.facet_counts.facet_fields; + var facet_data = {}; + _.each($scope.panel.fields, function (field) { + facet_data[field] = []; + for (var i = 0; i < facet_results[field].length; i += 2) { + facet_data[field].push({ + value: facet_results[field][i], + count: facet_results[field][i + 1] + }); + } + }); + $scope.facet_data = facet_data; + + // Keep only what we need for the set + $scope.data = $scope.data.slice(0, $scope.panel.size * $scope.panel.pages); + } else { + return; + } - // If we're not sorting in reverse chrono order, query every index for - // size*pages results - // Otherwise, only get size*pages results then stop querying - if ($scope.panel.sortable && ($scope.data.length < $scope.panel.size * $scope.panel.pages || !((_.contains(filterSrv.timeField(), $scope.panel.sort[0])) && $scope.panel.sort[1] === 'desc')) && - _segment + 1 < dashboard.indices.length) { - $scope.get_data(_segment + 1, $scope.query_id); - } + // If we're not sorting in reverse chrono order, query every index for + // size*pages results + // Otherwise, only get size*pages results then stop querying + if ($scope.panel.sortable && ($scope.data.length < $scope.panel.size * $scope.panel.pages || !((_.contains(filterSrv.timeField(), $scope.panel.sort[0])) && $scope.panel.sort[1] === 'desc')) && + _segment + 1 < dashboard.indices.length) { + $scope.get_data(_segment + 1, $scope.query_id); + } - }); + }); + } }; $scope.exportfile = function(filetype) { diff --git a/src/app/panels/fullTextSearch/pagination.html b/src/app/panels/fullTextSearch/pagination.html old mode 100755 new mode 100644 diff --git a/src/app/panels/gauge/editor.html b/src/app/panels/gauge/editor.html new file mode 100644 index 000000000..0bd381001 --- /dev/null +++ b/src/app/panels/gauge/editor.html @@ -0,0 +1,70 @@ +
+
+ + +
+
+ + +
+ + +
+ + +
+
+ + +
+ +
+
+
+ + +
+ +
+ + +
+
+ + +
+
+ + +
+ +
+ +
+ + +
+
+
+ + +
+
+ +
+
Real-time (Auto-refresh)
+
+ +
+
+ + +
+
+
+
Linkage Effective
+
+ +
+ +
diff --git a/src/app/panels/gauge/module.html b/src/app/panels/gauge/module.html new file mode 100644 index 000000000..c6a19b426 --- /dev/null +++ b/src/app/panels/gauge/module.html @@ -0,0 +1,109 @@ +
+ + +
+ +
+ + + + + + +
{{term.label}}{{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}
+ + +
+ {{term.label}} ({{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}) +

+ +
+
+ +
+ + + +
+ +
+ + + + + + +
{{term.label}}{{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}
+ + +
+ {{term.label}} ({{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}) +

+ +
+ + + + + + +
+
+
diff --git a/src/app/panels/gauge/module.js b/src/app/panels/gauge/module.js new file mode 100644 index 000000000..fc44657a8 --- /dev/null +++ b/src/app/panels/gauge/module.js @@ -0,0 +1,726 @@ +/* + ## Terms + + ### Parameters + * style :: A hash of css styles + * size :: top N + * arrangement :: How should I arrange the query results? 'horizontal' or 'vertical' + * chart :: Show a chart? 'none', 'bar', 'pie' + * donut :: Only applies to 'pie' charts. Punches a hole in the chart for some reason + * tilt :: Only 'pie' charts. Janky 3D effect. Looks terrible 90% of the time. + * lables :: Only 'pie' charts. Labels on the pie? +*/ +define([ + 'angular', + 'app', + 'underscore', + 'jquery', + 'kbn', + 'echarts', + 'd3' +], +function (angular, app, _, $, kbn) { + 'use strict'; + + var module = angular.module('kibana.panels.gauge', []); + app.useModule(module); + + module.controller('gauge', function($scope, $timeout, timer, querySrv, dashboard, filterSrv) { + $scope.panelMeta = { + + exportfile: true, + editorTabs : [ + {title:'Queries', src:'app/partials/querySelect.html'} + ], + status : "Stable", + description : "Displays the results of a Solr facet as a pie chart, bar chart, or a table. Newly added functionality displays min/max/mean/sum of a stats field, faceted by the Solr facet field, again as a pie chart, bar chart or a table." + }; + + // Set and populate defaults + var _d = { + queries : { + mode : 'all', + ids : [], + query : '*:*', + custom : '' + }, + mode : 'count', // mode to tell which number will be used to plot the chart. + field : '', + stats_field : '', + decimal_points : 0, // The number of digits after the decimal point + exclude : [], + display:'block', + icon:"icon-caret-down", + missing : false, + other : false, + size : 10000, + sortBy : 'count', + threshold_first:3000, + threshold_second:5000, + order : 'descending', + style : { "font-size": '10pt'}, + fontsize:20, + title_defined:false, + donut : false, + tilt : false, + labels : true, + logAxis : false, + arrangement : 'horizontal', + chart : 'bar', + counter_pos : 'above', + exportSize : 10000, + lastColor : '', + spyable : true, + linkage_id:'a', + show_queries:true, + error : '', + chartColors : querySrv.colors, + refresh: { + enable: false, + interval: 2 + } + }; + _.defaults($scope.panel,_d); + + $scope.init = function () { + $scope.hits = 0; + //$scope.testMultivalued(); + + // Start refresh timer if enabled + if ($scope.panel.refresh.enable) { + $scope.set_timer($scope.panel.refresh.interval); + } + + $scope.$on('refresh',function(){ + $scope.get_data(); + }); + + $scope.get_data(); + }; + + $scope.testMultivalued = function() { + if($scope.panel.field && $scope.fields.typeList[$scope.panel.field] && $scope.fields.typeList[$scope.panel.field].schema.indexOf("M") > -1) { + $scope.panel.error = "Can't proceed with Multivalued field"; + return; + } + + if($scope.panel.stats_field && $scope.fields.typeList[$scope.panel.stats_field].schema.indexOf("M") > -1) { + $scope.panel.error = "Can't proceed with Multivalued field"; + return; + } + }; + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; + /** + * + * + * @param {String} filetype -'json', 'xml', 'csv' + */ + $scope.build_query = function(filetype, isForExport) { + + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + } + var wt_json = '&wt=' + filetype; + var rows_limit = isForExport ? '&rows=0' : ''; // for terms, we do not need the actual response doc, so set rows=0 + var facet = ''; + + if ($scope.panel.mode === 'count') { + facet = '&facet=true&facet.field=' + $scope.panel.field + '&facet.limit=' + $scope.panel.size + '&facet.missing=true'; + } else { + // if mode != 'count' then we need to use stats query + // stats does not support something like facet.limit, so we have to sort and limit the results manually. + facet = '&stats=true&stats.facet=' + $scope.panel.field + '&stats.field=' + $scope.panel.stats_field + '&facet.missing=true'; + } + facet += '&f.' + $scope.panel.field + '.facet.sort=' + ($scope.panel.sortBy || 'count'); + + var exclude_length = $scope.panel.exclude.length; + var exclude_filter = ''; + if(exclude_length > 0){ + for (var i = 0; i < exclude_length; i++) { + if($scope.panel.exclude[i] !== "") { + exclude_filter += '&fq=-' + $scope.panel.field +":"+ $scope.panel.exclude[i]; + } + } + } + + return querySrv.getORquery() + wt_json + rows_limit + fq + exclude_filter + facet + ($scope.panel.queries.custom != null ? $scope.panel.queries.custom : ''); + }; + + $scope.exportfile = function(filetype) { + + var query = this.build_query(filetype, true); + + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + var request = $scope.sjs.Request().indices(dashboard.indices), + response; + + request.setQuery(query); + + response = request.doSearch(); + + // Populate scope when we have results + response.then(function(response) { + kbn.download_response(response, filetype, "terms"); + }); + }; + + $scope.set_timer = function(refresh_interval) { + $scope.panel.refresh.interval = refresh_interval; + if (_.isNumber($scope.panel.refresh.interval)) { + timer.cancel($scope.refresh_timer); + $scope.realtime(); + } else { + timer.cancel($scope.refresh_timer); + } + }; + + $scope.realtime = function() { + if ($scope.panel.refresh.enable) { + timer.cancel($scope.refresh_timer); + + $scope.refresh_timer = timer.register($timeout(function() { + $scope.realtime(); + $scope.get_data(); + }, $scope.panel.refresh.interval*1000)); + } else { + timer.cancel($scope.refresh_timer); + } + }; + + $scope.get_data = function() { + if(($scope.panel.linkage_id === dashboard.current.linkage_id)||dashboard.current.enable_linkage){ + // Make sure we have everything for the request to complete + if (dashboard.indices.length === 0) { + return; + } + + delete $scope.panel.error; + $scope.panelMeta.loading = true; + var request, results; + + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + request = $scope.sjs.Request().indices(dashboard.indices); + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + + // Populate the inspector panel + $scope.inspector = angular.toJson(JSON.parse(request.toString()), true); + + var query = this.build_query('json', false); + + // Set the panel's query + $scope.panel.queries.query = query; + + request.setQuery(query); + + results = request.doSearch(); + + // Populate scope when we have results + results.then(function (results) { + // Check for error and abort if found + if (!(_.isUndefined(results.error))) { + $scope.panel.error = $scope.parse_error(results.error.msg); + $scope.data = []; + $scope.panelMeta.loading = false; + $scope.$emit('render'); + return; + } + + + + var sum = 0; + var k = 0; + var missing = 0; + $scope.panelMeta.loading = false; + $scope.hits = results.response.numFound; + $scope.data = []; + + var AP_1 = 0.0; + var AP_2 = 0.0; + var AP_n = 0.0; + if ($scope.panel.mode === 'count') { + // In count mode, the y-axis min should be zero because count value cannot be negative. + $scope.yaxis_min = 0; + _.each(results.facet_counts.facet_fields, function (v) { + for (var i = 0; i < v.length; i++) { + var term = v[i]; + i++; + var count = v[i]; + sum += count; + + if (term === null) { + missing = count; + } else { + // if count = 0, do not add it to the chart, just skip it + if (count === 0) { + continue; + } + AP_n += count; + if (parseInt(term) <= $scope.panel.threshold_first) { + AP_1 += count; + } else if (parseInt(term) < $scope.panel.threshold_second && parseInt(term) > $scope.panel.threshold_first) { + AP_2 += count * 0.5; + } + + } + } + }); + $scope.apdex = 100; + if (AP_n !== 0) { + $scope.apdex = parseInt(100 * (AP_1 + AP_2) / AP_n); + } + } else { + // In stats mode, set y-axis min to null so jquery.flot will set the scale automatically. + $scope.yaxis_min = null; + _.each(results.stats.stats_fields[$scope.panel.stats_field].facets[$scope.panel.field], function (stats_obj, facet_field) { + var slice = {label: facet_field, data: [[k, stats_obj[$scope.panel.mode]]], actions: true}; + $scope.data.push(slice); + }); + } + // Sort the results + $scope.data = _.sortBy($scope.data, function (d) { + return $scope.panel.sortBy === 'index' ? d.label : d.data[0][1]; + }); + if ($scope.panel.order === 'descending') { + $scope.data.reverse(); + } + + // Slice it according to panel.size, and then set the x-axis values with k. + $scope.data = $scope.data.slice(0, $scope.panel.size); + _.each($scope.data, function (v) { + v.data[0][0] = k; + k++; + }); + + if ($scope.panel.field && $scope.fields.typeList[$scope.panel.field] && $scope.fields.typeList[$scope.panel.field].schema.indexOf("T") > -1) { + $scope.hits = sum; + } + + $scope.data.push({ + label: 'Missing field', + // data:[[k,results.facets.terms.missing]],meta:"missing",color:'#aaa',opacity:0}); + // TODO: Hard coded to 0 for now. Solr faceting does not provide 'missing' value. + data: [[k, missing]], meta: "missing", color: '#aaa', opacity: 0 + }); + $scope.data.push({ + label: 'Other values', + // data:[[k+1,results.facets.terms.other]],meta:"other",color:'#444'}); + // TODO: Hard coded to 0 for now. Solr faceting does not provide 'other' value. + data: [[k + 1, $scope.hits - sum]], meta: "other", color: '#444' + }); + + $scope.$emit('render'); + }); + } + }; + + $scope.build_search = function(term,negate) { + + if (_.isUndefined(term.meta)) { + filterSrv.set({ + type: 'terms', field: $scope.panel.field, value: term.label, + mandate: (negate ? 'mustNot' : 'must') + }); + } else if (term.meta === 'missing') { + filterSrv.set({ + type: 'exists', field: $scope.panel.field, + mandate: (negate ? 'must' : 'mustNot') + }); + } else { + return; + } + dashboard.current.linkage_id = $scope.panel.linkage_id; + dashboard.current.enable_linkage = false; + dashboard.refresh(); + + }; + + $scope.set_refresh = function (state) { + $scope.refresh = state; + // if 'count' mode is selected, set decimal_points to zero automatically. + if ($scope.panel.mode === 'count') { + $scope.panel.decimal_points = 0; + } + }; + + $scope.close_edit = function() { + // Start refresh timer if enabled + if ($scope.panel.refresh.enable) { + $scope.set_timer($scope.panel.refresh.interval); + } + + if ($scope.refresh) { + // $scope.testMultivalued(); + $scope.get_data(); + } + $scope.refresh = false; + $scope.$emit('render'); + }; + + $scope.showMeta = function(term) { + if(_.isUndefined(term.meta)) { + return true; + } + if(term.meta === 'other' && !$scope.panel.other) { + return false; + } + if(term.meta === 'missing' && !$scope.panel.missing) { + return false; + } + return true; + }; + + }); + + module.directive('gaugeChart', function(querySrv,dashboard) { + return { + restrict: 'A', + link: function(scope, elem) { + var myChart; + // Receive render events + scope.$on('render',function(){ + render_panel(); + }); + + // Re-render if the window is resized + angular.element(window).bind('resize', function(){ + render_panel(); + }); + + // Function for rendering panel + function render_panel() { + + elem.html(""); + + // IE doesn't work without this + elem.css({height:scope.panel.height||scope.row.height}); + + // Make a clone we can operate on. + + var idd = scope.$id; + var echarts = require('echarts'); + + + var audio = document.getElementById("bgMusic"); + + // Populate element + try { + + var labelcolor = false; + if (dashboard.current.style === 'dark'){ + labelcolor = true; + } + // Add plot to scope so we can build out own legend + if(scope.panel.chart === 'gauge') { + if(scope.apdex<80){ + //var audio = new Audio("vendor/alarm/alarm.wav"); + dashboard.current.alarm = true; + audio.play(); + audio.muted = dashboard.current.mute; + + } + + if(scope.apdex>=80&&dashboard.current.alarm){ + dashboard.current.alarm = false; + audio.pause(); + audio.currentTime = 0; + } + + var term = "告警"; + var color_term = "#F6AB60"; + if(scope.apdex<=20){ + term = "风险"; + color_term = '#EB5768'; + }else if(scope.apdex>60){ + term = "å¥åº·"; + color_term = '#1e90ff'; + } + if(myChart) { + myChart.dispose(); + } + myChart = echarts.init(document.getElementById(idd)); + + + var option = { + toolbox: { + show : false, + feature : { + mark : {show: false}, + restore : {show: false}, + saveAsImage : {show: false} + } + }, + grid: { + left: '0%', + right: '0%', + bottom: '0%', + top: 90 + }, + series : [ + { + name:'Health', + type:'gauge', + min:100, + max:0, + splitNumber:10, + radius: '96%', + axisLine: { // åæ ‡è½´çº¿ + lineStyle: { // 属性lineStyleæŽ§åˆ¶çº¿æ¡æ ·å¼ + color: [[0.6, '#1e90ff'],[0.82, '#F6AB60'],[1, '#EB5768']], + width: 5, + //é»˜è®¤é€æ˜Ž + shadowBlur: 50, + type:'dotted', + shadowColor : '#ddfdfa', + opacity:labelcolor?1:0 + } + }, + axisLabel: { // åæ ‡è½´å°æ ‡è®° + textStyle: { // 属性lineStyleæŽ§åˆ¶çº¿æ¡æ ·å¼ + fontWeight: 'bolder', + color: labelcolor?'#fff':'#696969', + shadowColor : '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 40, + fontStyle: 'italic', + fontSize:scope.panel.fontsize + } + }, + axisTick: { // åæ ‡è½´å°æ ‡è®° + length :15, // 属性length控制线长 + lineStyle: { // 属性lineStyleæŽ§åˆ¶çº¿æ¡æ ·å¼ + color: 'auto', + width:3, + type:'dotted', + shadowColor : labelcolor?'#fff':'#00008B', + shadowBlur: 50 + } + }, + splitLine: { // 分隔线 + length :25, // 属性length控制线长 + lineStyle: { // 属性lineStyle(详è§lineStyleï¼‰æŽ§åˆ¶çº¿æ¡æ ·å¼ + width:2, + color: labelcolor?'#fff':'auto', + type:'dotted', + shadowColor : labelcolor?'#fff':'#f55351', //é»˜è®¤é€æ˜Ž + shadowBlur: 25 + } + }, + pointer: { // 分隔线 + length:'90%', + width:2 + }, + itemStyle:{ + + normal:{ + color:'#f55351', + shadowColor: '#f55351', + shadowBlur: 30, + borderWidth:2, + borderColor: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, color: '#f55351' // 0% 处的颜色 + }, { + offset: 0.86, color: '#f8750d' // 100% 处的颜色 + },{ + offset: 1, color: '#fff' // 100% 处的颜色 + }], false) + }, + emphasis:{ + color:'#f55351', + shadowColor: '#f55351', + shadowBlur: 30, + borderWidth:2, + borderColor: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, color: 'red' // 0% 处的颜色 + }, { + offset: 0.86, color: '#50d1f1' // 100% 处的颜色 + },{ + offset: 1, color: '#fff' // 100% 处的颜色 + }], false) + + } + }, + title : { + textStyle: { // 其余属性默认使用全局文本样å¼ï¼Œè¯¦è§TEXTSTYLE + fontWeight: 'bolder', + fontSize: scope.panel.fontsize+14, + fontStyle: 'italic', + color: labelcolor?'#fff':'#696969', + shadowColor : '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 40 + } + }, + detail : { + formatter:term+'\n\n\n{value}%', + // x, y,å•ä½px + textStyle: { // 其余属性默认使用全局文本样å¼ï¼Œè¯¦è§TEXTSTYLE + fontWeight: 'bolder', + color: color_term, + fontSize:scope.panel.fontsize+12 + } + }, + data:[{value: scope.apdex, name:scope.panel.title_defined? scope.panel.title:'Health State'}] + } + + ] + }; + + + + +var option_health_nodata = { + + + toolbox: { + show : false, + feature : { + mark : {show: false}, + restore : {show: false}, + saveAsImage : {show: false} + } + }, + grid: { + left: '0%', + right: '0%', + bottom: '0%', + top: 90 + }, + series : [ + { + name:'Health', + + type:'gauge', + min:100, + max:0, + splitNumber:10, + radius: '96%', + axisLine: { // åæ ‡è½´çº¿ + lineStyle: { // 属性lineStyleæŽ§åˆ¶çº¿æ¡æ ·å¼ + color: [[0.6, '#1e90ff'],[0.82, '#F6AB60'],[1, '#EB5768']], + width: 5, + shadowColor : '#ddfdfa', //é»˜è®¤é€æ˜Ž + shadowBlur: 40 + } + }, + axisLabel: { // åæ ‡è½´å°æ ‡è®° + textStyle: { // 属性lineStyleæŽ§åˆ¶çº¿æ¡æ ·å¼ + fontWeight: 'bolder', + color: labelcolor?'#fff':'#696969', + shadowColor : '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 40, + fontStyle: 'italic', + fontSize:scope.panel.fontsize + } + }, + axisTick: { // åæ ‡è½´å°æ ‡è®° + length :18, // 属性length控制线长 + lineStyle: { // 属性lineStyleæŽ§åˆ¶çº¿æ¡æ ·å¼ + color: 'auto', + shadowColor : '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 40 + } + }, + splitLine: { // 分隔线 + length :28, // 属性length控制线长 + lineStyle: { // 属性lineStyle(详è§lineStyleï¼‰æŽ§åˆ¶çº¿æ¡æ ·å¼ + width:4, + color: '#fff', + shadowColor : '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 40 + } + }, + pointer: { // 分隔线 + length:'90%', + width:3 + }, + itemStyle:{ + normal:{ + color:'#fff', + shadowColor: '#f55351', + shadowBlur: 30, + borderWidth:2, + borderColor: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, color: 'red' // 0% 处的颜色 + }, { + offset: 0.7, color: '#f8750d' // 100% 处的颜色 + },{ + offset: 1, color: '#fff' // 100% 处的颜色 + }], false) + }, + emphasis:{ + color:'#fff', + shadowColor: '#fff', + shadowBlur: 30, + borderWidth:2, + borderColor: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, color: 'red' // 0% 处的颜色 + }, { + offset: 0.7, color: '#50d1f1' // 100% 处的颜色 + },{ + offset: 1, color: '#fff' // 100% 处的颜色 + }], false) + + } + }, + title : { + textStyle: { // 其余属性默认使用全局文本样å¼ï¼Œè¯¦è§TEXTSTYLE + fontWeight: 'bolder', + fontSize: scope.panel.fontsize+15, + fontStyle: 'italic', + color: labelcolor?'#fff':'#696969', + shadowColor : '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 40 + } + }, + detail : { + formatter:'{value}%', + // x, y,å•ä½px + textStyle: { // 其余属性默认使用全局文本样å¼ï¼Œè¯¦è§TEXTSTYLE + fontWeight: 'bolder', + color: labelcolor?'#fff':'#696969', + fontSize:scope.panel.fontsize+10 + } + }, + data:[{value: 0, name: scope.panel.title_defined? scope.panel.title+'(no data)':'Health State(no data)'}] + } + + ] +}; + + if(scope.hits === 0){ + myChart.setOption(option_health_nodata);}else{ + myChart.setOption(option); + } + // 使用刚指定的é…ç½®é¡¹å’Œæ•°æ®æ˜¾ç¤ºå›¾è¡¨ã€‚ + + } + + // Populate legend + + + } catch(e) { + elem.text(e); + } + + } + + + + + } + }; + }); + +}); diff --git a/src/app/panels/glmap/editor.html b/src/app/panels/glmap/editor.html new file mode 100644 index 000000000..b272f1986 --- /dev/null +++ b/src/app/panels/glmap/editor.html @@ -0,0 +1,121 @@ +
+
+ + +
+
+ + +
+
+ + +
+
+ + + +
+
+ + +
+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+
+
Real-time (Auto-refresh)
+
+ +
+
+ + +
+
+
+
Linkage Effective
+
+ +
+ +
diff --git a/src/app/panels/glmap/module.html b/src/app/panels/glmap/module.html new file mode 100644 index 000000000..dbc992216 --- /dev/null +++ b/src/app/panels/glmap/module.html @@ -0,0 +1,55 @@ +
+ + + + + +
+ + + + + + + + +
+
diff --git a/src/app/panels/glmap/module.js b/src/app/panels/glmap/module.js new file mode 100644 index 000000000..07bd3dec9 --- /dev/null +++ b/src/app/panels/glmap/module.js @@ -0,0 +1,1002 @@ +/* + ## pies + + ### Parameters + * style :: A hash of css styles + * size :: top N + * arrangement :: How should I arrange the query results? 'horizontal' or 'vertical' + * chart :: Show a chart? 'none', 'bar', 'pie' + * donut :: Only applies to 'pie' charts. Punches a hole in the chart for some reason + * tilt :: Only 'pie' charts. Janky 3D effect. Looks terrible 90% of the time. + * lables :: Only 'pie' charts. Labels on the pie? +*/ +define([ + 'angular', + 'app', + 'underscore', + 'jquery', + 'kbn' +], +function (angular, app, _, $, kbn) { + 'use strict'; + + var module = angular.module('kibana.panels.glmap', []); + app.useModule(module); + + module.controller('glmap', function($scope, $timeout, timer, querySrv, dashboard, filterSrv) { + $scope.panelMeta = { + exportfile: true, + editorTabs : [ + {title:'Queries', src:'app/partials/querySelect.html'} + ], + status : "Stable", + description : "Displays the results of a Solr facet as a pie chart, bar chart, or a table. Newly added functionality displays min/max/mean/sum of a stats field, faceted by the Solr facet field, again as a pie chart, bar chart or a table." + }; + + // Set and populate defaults + var _d = { + queries : { + mode : 'all', + ids : [], + query : '*:*', + custom : '' + }, + mode : 'count', // mode to tell which number will be used to plot the chart. + field : '', + stats_field : '', + decimal_points : 0, // The number of digits after the decimal point + exclude : [], + missing : false, + other : false, + size : 10000, + sortBy : 'count', + order : 'descending', + fontsize : 12, + donut : false, + tilt : false, + display:'block', + icon:"icon-caret-down", + labels : true, + ylabels :true, + linkage_id:'a', + logAxis : false, + arrangement : 'vertical', + RoseType : 'area', + chart : 'bar3d', + exportSize : 10000, + value_sort:'rs_timestamp', + defaulttimestamp:true, + lastColor : '', + spyable : true, + show_queries:true, + error : '', + chartColors : querySrv.colors, + refresh: { + enable: false, + interval: 2 + } + }; + _.defaults($scope.panel,_d); + + $scope.init = function () { + $scope.hits = 0; + //$scope.testMultivalued(); + + // Start refresh timer if enabled + if ($scope.panel.refresh.enable) { + $scope.set_timer($scope.panel.refresh.interval); + } + + $scope.$on('refresh',function(){ + $scope.get_data(); + }); + + $scope.get_data(); + }; + + $scope.testMultivalued = function() { + if($scope.panel.field && $scope.fields.typeList[$scope.panel.field] && $scope.fields.typeList[$scope.panel.field].schema.indexOf("M") > -1) { + $scope.panel.error = "Can't proceed with Multivalued field"; + return; + } + + if($scope.panel.stats_field && $scope.fields.typeList[$scope.panel.stats_field].schema.indexOf("M") > -1) { + $scope.panel.error = "Can't proceed with Multivalued field"; + return; + } + }; + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; + /** + * + * + * @param {String} filetype -'json', 'xml', 'csv' + */ + $scope.build_query = function(filetype, isForExport) { + + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + if(!$scope.panel.defaulttimestamp){ + fq = fq.replace(filterSrv.getTimeField(),$scope.panel.value_sort); + } + } + var wt_json = '&wt=' + filetype; + var rows_limit = isForExport ? '&rows=0' : ''; // for pies, we do not need the actual response doc, so set rows=0 + var facet = ''; + + if ($scope.panel.mode === 'count') { + facet = '&facet=true&facet.field=' + $scope.panel.field + '&facet.limit=' + $scope.panel.size + '&facet.missing=true'; + } else { + // if mode != 'count' then we need to use stats query + // stats does not support something like facet.limit, so we have to sort and limit the results manually. + facet = '&stats=true&stats.facet=' + $scope.panel.field + '&stats.field=' + $scope.panel.stats_field + '&facet.missing=true'; + } + facet += '&f.' + $scope.panel.field + '.facet.sort=' + ($scope.panel.sortBy || 'count'); + + var exclude_length = $scope.panel.exclude.length; + var exclude_filter = ''; + if(exclude_length > 0){ + for (var i = 0; i < exclude_length; i++) { + if($scope.panel.exclude[i] !== "") { + exclude_filter += '&fq=-' + $scope.panel.field +":"+ $scope.panel.exclude[i]; + } + } + } + + return querySrv.getORquery() + wt_json + rows_limit + fq + exclude_filter + facet + ($scope.panel.queries.custom != null ? $scope.panel.queries.custom : ''); + }; + + $scope.exportfile = function(filetype) { + + var query = this.build_query(filetype, true); + + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + var request = $scope.sjs.Request().indices(dashboard.indices), + response; + + request.setQuery(query); + + response = request.doSearch(); + + // Populate scope when we have results + response.then(function(response) { + kbn.download_response(response, filetype, "pies"); + }); + }; + + $scope.set_timer = function(refresh_interval) { + $scope.panel.refresh.interval = refresh_interval; + if (_.isNumber($scope.panel.refresh.interval)) { + timer.cancel($scope.refresh_timer); + $scope.realtime(); + } else { + timer.cancel($scope.refresh_timer); + } + }; + + $scope.realtime = function() { + if ($scope.panel.refresh.enable) { + timer.cancel($scope.refresh_timer); + + $scope.refresh_timer = timer.register($timeout(function() { + $scope.realtime(); + $scope.get_data(); + }, $scope.panel.refresh.interval*1000)); + } else { + timer.cancel($scope.refresh_timer); + } + }; + + $scope.get_data = function() { + if(($scope.panel.linkage_id === dashboard.current.linkage_id)||dashboard.current.enable_linkage){ + // Make sure we have everything for the request to complete + if (dashboard.indices.length === 0) { + return; + } + + delete $scope.panel.error; + $scope.panelMeta.loading = true; + var request, results; + + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + request = $scope.sjs.Request().indices(dashboard.indices); + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + + // Populate the inspector panel + $scope.inspector = angular.toJson(JSON.parse(request.toString()), true); + + var query = this.build_query('json', false); + + // Set the panel's query + $scope.panel.queries.query = query; + + request.setQuery(query); + + results = request.doSearch(); + + // Populate scope when we have results + results.then(function (results) { + // Check for error and abort if found + if (!(_.isUndefined(results.error))) { + $scope.panel.error = $scope.parse_error(results.error.msg); + $scope.data = []; + $scope.label = []; + $scope.panelMeta.loading = false; + $scope.$emit('render'); + return; + } + + // Function for validating HTML color by assign it to a dummy
+ // and let the browser do the work of validation. + + + // Function for customizing chart color by using field values as colors. + + + var sum = 0; + var k = 0; + var missing = 0; + $scope.panelMeta.loading = false; + $scope.hits = results.response.numFound; + $scope.data = []; + $scope.label = []; + $scope.radardata = []; + $scope.maxdata = 0; + + + if ($scope.panel.mode === 'count') { + // In count mode, the y-axis min should be zero because count value cannot be negative. + $scope.yaxis_min = 0; + + _.each(results.facet_counts.facet_fields, function (v) { + for (var i = 0; i < v.length; i++) { + var term = v[i]; + i++; + var count = v[i]; + + + if (term === null) { + missing = count; + } else { + // if count = 0, do not add it to the chart, just skip it + if (count === 0) { + continue; + } + var terms = term.split(","); + + + var slice = [parseFloat(terms[1]), parseFloat(terms[0]), count]; + $scope.label.push(term); + $scope.data.push(slice); + $scope.radardata.push(count); + } + } + }); + } else { + // In stats mode, set y-axis min to null so jquery.flot will set the scale automatically. + $scope.yaxis_min = null; + _.each(results.stats.stats_fields[$scope.panel.stats_field].facets[$scope.panel.field], function (stats_obj, facet_field) { + var slice = {label: facet_field, data: [[k, stats_obj[$scope.panel.mode]]], actions: true}; + $scope.data.push(slice); + }); + } + // Sort the results + $scope.data = _.sortBy($scope.data, function (d) { + return $scope.panel.sortBy === 'index' ? d.name : d.value; + }); + if ($scope.panel.order === 'descending') { + $scope.data.reverse(); + $scope.label.reverse(); + $scope.radardata.reverse(); + } + + // Slice it according to panel.size, and then set the x-axis values with k. + // $scope.data = $scope.data.slice(0,$scope.panel.size); + //_.each($scope.data, function(v) { + // v.data[0][0] = k; + // k++; + // }); + + if ($scope.panel.field && $scope.fields.typeList[$scope.panel.field] && $scope.fields.typeList[$scope.panel.field].schema.indexOf("T") > -1) { + $scope.hits = sum; + } + + // $scope.data.push({label:'Missing field', + // data:[[k,results.facets.pies.missing]],meta:"missing",color:'#aaa',opacity:0}); + // TODO: Hard coded to 0 for now. Solr faceting does not provide 'missing' value. + //data:[[k,missing]],meta:"missing",color:'#aaa',opacity:0}); + // $scope.data.push({label:'Other values', + // data:[[k+1,results.facets.pies.other]],meta:"other",color:'#444'}); + // TODO: Hard coded to 0 for now. Solr faceting does not provide 'other' value. + // data:[[k+1,$scope.hits-sum]],meta:"other",color:'#444'}); + + $scope.$emit('render'); + }); + } + }; + + $scope.build_search = function(term,negate) { + + if (_.isUndefined(term.meta)) { + filterSrv.set({ + type: 'terms', field: $scope.panel.field, value: term.name, + mandate: (negate ? 'mustNot' : 'must') + }); + } else if (term.meta === 'missing') { + filterSrv.set({ + type: 'exists', field: $scope.panel.field, + mandate: (negate ? 'must' : 'mustNot') + }); + } else { + return; + } + dashboard.current.linkage_id = $scope.panel.linkage_id; + dashboard.current.enable_linkage = false; + dashboard.refresh(); + + }; + + $scope.set_refresh = function (state) { + $scope.refresh = state; + // if 'count' mode is selected, set decimal_points to zero automatically. + if ($scope.panel.mode === 'count') { + $scope.panel.decimal_points = 0; + } + }; + + $scope.close_edit = function() { + // Start refresh timer if enabled + if ($scope.panel.refresh.enable) { + $scope.set_timer($scope.panel.refresh.interval); + } + + if ($scope.refresh) { + // $scope.testMultivalued(); + $scope.get_data(); + } + $scope.refresh = false; + $scope.$emit('render'); + }; + + $scope.showMeta = function(term) { + if(_.isUndefined(term.meta)) { + return true; + } + if(term.meta === 'other' && !$scope.panel.other) { + return false; + } + if(term.meta === 'missing' && !$scope.panel.missing) { + return false; + } + return true; + }; + + }); + + module.directive('glmapChart', function(querySrv,dashboard,filterSrv) { + return { + restrict: 'A', + link: function(scope, elem) { + var myChart; + // Receive render events + scope.$on('render',function(){ + render_panel(); + }); + + // Re-render if the window is resized + angular.element(window).bind('resize', function(){ + render_panel(); + }); + + // Function for rendering panel + function render_panel() { + + var colors = []; + + // IE doesn't work without this + elem.css({height:scope.panel.height||scope.row.height}); + + // Make a clone we can operate on. + + + + if (filterSrv.idsByTypeAndField('pies',scope.panel.field).length > 0) { + colors.push(scope.panel.lastColor); + } else { + colors = scope.panel.chartColors; + } + +var option_nodata = { + series: [{ + + type: 'wordCloud', + //size: ['9%', '99%'], + sizeRange: [50, 50], + //textRotation: [0, 45, 90, -45], + rotationRange: [0, 0], + //shape: 'circle', + textPadding: 0, + autoSize: { + enable: true, + minSize: 6 + }, + textStyle: { + normal: { + color: '#1a93f9' + }, + emphasis: { + shadowBlur: 10, + shadowColor: '#333' + } + }, + data: [{ + name: "NO DATA", + value: 1 + }] + }] +}; + + + var idd = scope.$id; + require(['echarts','echarts-gl'], function(ec,gl){ + var echarts = ec; + if(myChart) { + myChart.dispose(); + } + //var echarts = require('echarts'); + + //require(['echartsgl'], function(){ + // Populate element + try { + var labelcolor = false; + if (dashboard.current.style === 'dark'){ + labelcolor = true; + } + // Add plot to scope so we can build out own legend + + if(scope.panel.chart === 'bar3d') { + + var hours = ['12a', '1a', '2a', '3a', '4a', '5a', '6a', + '7a', '8a', '9a','10a','11a', + '12p', '1p', '2p', '3p', '4p', '5p', + '6p', '7p', '8p', '9p', '10p', '11p']; + var days = ['Saturday', 'Friday', 'Thursday', + 'Wednesday', 'Tuesday', 'Monday', 'Sunday']; + + var data = [[0,0,5],[0,1,1],[0,2,0],[0,3,0],[0,4,0], + [0,5,0],[0,6,0],[0,7,0],[0,8,0],[0,9,0],[0,10,0], + [0,11,2],[0,12,4],[0,13,1],[0,14,1],[0,15,3],[0,16,4], + [0,17,6],[0,18,4],[0,19,4],[0,20,3],[0,21,3],[0,22,2], + [0,23,5],[1,0,7],[1,1,0],[1,2,0],[1,3,0],[1,4,0],[1,5,0], + [1,6,0],[1,7,0],[1,8,0],[1,9,0],[1,10,5],[1,11,2],[1,12,2], + [1,13,6],[1,14,9],[1,15,11],[1,16,6],[1,17,7],[1,18,8],[1,19,12], + [1,20,5],[1,21,5],[1,22,7],[1,23,2],[2,0,1],[2,1,1],[2,2,0],[2,3,0], + [2,4,0],[2,5,0],[2,6,0],[2,7,0],[2,8,0],[2,9,0],[2,10,3],[2,11,2],[2,12,1], + [2,13,9],[2,14,8],[2,15,10],[2,16,6],[2,17,5],[2,18,5],[2,19,5],[2,20,7],[2,21,4], + [2,22,2],[2,23,4],[3,0,7],[3,1,3],[3,2,0],[3,3,0],[3,4,0],[3,5,0],[3,6,0],[3,7,0],[3,8,1], + [3,9,0],[3,10,5],[3,11,4],[3,12,7],[3,13,14],[3,14,13],[3,15,12],[3,16,9],[3,17,5],[3,18,5],[3,19,10], + [3,20,6],[3,21,4],[3,22,4],[3,23,1],[4,0,1],[4,1,3],[4,2,0],[4,3,0],[4,4,0],[4,5,1],[4,6,0],[4,7,0],[4,8,0], + [4,9,2],[4,10,4],[4,11,4],[4,12,2],[4,13,4],[4,14,4],[4,15,14],[4,16,12],[4,17,1],[4,18,8],[4,19,5],[4,20,3],[4,21,7], + [4,22,3],[4,23,0],[5,0,2],[5,1,1],[5,2,0],[5,3,3],[5,4,0],[5,5,0],[5,6,0],[5,7,0],[5,8,2],[5,9,0],[5,10,4],[5,11,1],[5,12,5], + [5,13,10],[5,14,5],[5,15,7],[5,16,11],[5,17,6],[5,18,0],[5,19,5],[5,20,3],[5,21,4],[5,22,2],[5,23,0],[6,0,1],[6,1,0],[6,2,0],[6,3,0], + [6,4,0],[6,5,0],[6,6,0],[6,7,0],[6,8,0],[6,9,0],[6,10,1],[6,11,0],[6,12,2],[6,13,1],[6,14,3],[6,15,4],[6,16,0],[6,17,0],[6,18,0],[6,19,0], + [6,20,1],[6,21,2],[6,22,2],[6,23,6]]; + myChart = echarts.init(document.getElementById(idd)); + var option33 = { + tooltip: {}, + visualMap: { + max: 20, + inRange: { + color: ['#313695', '#4575b4', '#74add1', '#abd9e9', '#e0f3f8', '#ffffbf', '#fee090', '#fdae61', '#f46d43', '#d73027', '#a50026'] + } + }, + xAxis3D: { + type: 'category', + axisLabel:{ + textStyle:{ + color:'#fff' + } + }, + data: hours + }, + yAxis3D: { + type: 'category', + axisLabel:{ + textStyle:{ + color:'#fff' + } + }, + data: days + }, + zAxis3D: { + axisLabel:{ + textStyle:{ + color:'#fff' + } + }, + type: 'value' + }, + grid3D: { + boxWidth: 200, + boxDepth: 80, + light: { + main: { + intensity: 1.2 + }, + ambient: { + intensity: 0.3 + } + } + }, + series: [{ + type: 'bar3D', + data: data.map(function (item) { + return { + value: [item[1], item[0], item[2]] + }; + }), + shading: 'color', + + label: { + show: false, + textStyle: { + fontSize: 16, + borderWidth: 1 + } + }, + + itemStyle: { + opacity: 0.4 + }, + + emphasis: { + label: { + textStyle: { + fontSize: 20, + color: '#900' + } + }, + itemStyle: { + color: '#900' + } + } + }] + }; + //æ²¡æœ‰æ•°æ®æ˜¾ç¤ºNO DATA + + if(scope.data.length === 0){ + myChart.setOption(option_nodata);}else{ + myChart.setOption(option33); + myChart.on('click', function (params) { + // 点击è”动 + scope.build_search(params); + }); + } + + } + + if(scope.panel.chart === 'bar') { + + myChart = echarts.init(document.getElementById(idd)); + + var hours1 = ['12a', '1a', '2a', '3a', '4a', '5a', '6a', + '7a', '8a', '9a','10a','11a', + '12p', '1p', '2p', '3p', '4p', '5p', + '6p', '7p', '8p', '9p', '10p', '11p']; + var days1 = ['Saturday', 'Friday', 'Thursday', + 'Wednesday', 'Tuesday', 'Monday', 'Sunday']; + + var data1 = [[0,0,5],[0,1,1],[0,2,0],[0,3,0],[0,4,0],[0,5,0],[0,6,0],[0,7,0],[0,8,0],[0,9,0],[0,10,0],[0,11,2],[0,12,4],[0,13,1],[0,14,1],[0,15,3],[0,16,4],[0,17,6],[0,18,4],[0,19,4],[0,20,3],[0,21,3],[0,22,2],[0,23,5], + [1,0,7],[1,1,0],[1,2,0],[1,3,0],[1,4,0],[1,5,0],[1,6,0],[1,7,0],[1,8,0],[1,9,0],[1,10,5],[1,11,2],[1,12,2],[1,13,6],[1,14,9],[1,15,11],[1,16,6],[1,17,7],[1,18,8],[1,19,12],[1,20,5],[1,21,5],[1,22,7],[1,23,2],[2,0,1],[2,1,1], + [2,2,0],[2,3,0],[2,4,0],[2,5,0],[2,6,0],[2,7,0],[2,8,0],[2,9,0],[2,10,3],[2,11,2],[2,12,1],[2,13,9],[2,14,8],[2,15,10],[2,16,6],[2,17,5],[2,18,5],[2,19,5],[2,20,7],[2,21,4],[2,22,2],[2,23,4],[3,0,7],[3,1,3],[3,2,0],[3,3,0],[3,4,0], + [3,5,0],[3,6,0],[3,7,0],[3,8,1],[3,9,0],[3,10,5],[3,11,4],[3,12,7],[3,13,14],[3,14,13],[3,15,12],[3,16,9],[3,17,5],[3,18,5],[3,19,10],[3,20,6],[3,21,4],[3,22,4],[3,23,1],[4,0,1],[4,1,3],[4,2,0],[4,3,0],[4,4,0],[4,5,1],[4,6,0],[4,7,0],[4,8,0], + [4,9,2],[4,10,4],[4,11,4],[4,12,2],[4,13,4],[4,14,4],[4,15,14],[4,16,12],[4,17,1],[4,18,8],[4,19,5],[4,20,3],[4,21,7],[4,22,3],[4,23,0],[5,0,2],[5,1,1],[5,2,0],[5,3,3],[5,4,0],[5,5,0],[5,6,0],[5,7,0],[5,8,2],[5,9,0],[5,10,4],[5,11,1],[5,12,5],[5,13,10], + [5,14,5],[5,15,7],[5,16,11],[5,17,6],[5,18,0],[5,19,5],[5,20,3],[5,21,4],[5,22,2],[5,23,0],[6,0,1],[6,1,0],[6,2,0],[6,3,0],[6,4,0],[6,5,0],[6,6,0],[6,7,0],[6,8,0],[6,9,0],[6,10,1],[6,11,0],[6,12,2],[6,13,1],[6,14,3],[6,15,4],[6,16,0],[6,17,0],[6,18,0],[6,19,0],[6,20,1],[6,21,2],[6,22,2],[6,23,6]]; + var option2 = { + tooltip: {}, + visualMap: { + max: 20, + inRange: { + color: ['#313695', '#4575b4', '#74add1', '#abd9e9', '#e0f3f8', '#ffffbf', '#fee090', '#fdae61', '#f46d43', '#d73027', '#a50026'] + } + }, + xAxis3D: { + type: 'category', + nameTextStyle:{ + color:'#fff' + }, + axisLabel:{ + textStyle:{ + color:'#fff' + } + }, + data: hours1 + }, + yAxis3D: { + type: 'category', + nameTextStyle:{ + color:'#fff' + }, + axisLabel:{ + textStyle:{ + color:'#fff' + } + }, + data: days1 + }, + zAxis3D: { + nameTextStyle:{ + color:'#fff' + }, + axisLabel:{ + textStyle:{ + color:'#fff' + } + }, + type: 'value' + }, + grid3D: { + boxWidth: 200, + boxDepth: 80, + viewControl: { + // projection: 'orthographic' + }, + light: { + main: { + intensity: 1.2, + shadow: true + }, + ambient: { + intensity: 0.3 + } + } + }, + series: [{ + type: 'bar3D', + data: data1.map(function (item) { + return { + value: [item[1], item[0], item[2]], + }; + }), + shading: 'lambert', + + label: { + textStyle: { + fontSize: 16, + borderWidth: 1 + } + }, + + emphasis: { + label: { + textStyle: { + fontSize: 20, + color: '#fff' + } + }, + itemStyle: { + color: '#900' + } + } + }] + }; + + + if(scope.data.length === 0){ + myChart.setOption(option_nodata);}else{ + myChart.setOption(option2); + myChart.on('click', function (params) { + // 点击è”动 + scope.build_search(params); + }); + } + } + + if(scope.panel.chart === 'flow') { + + myChart = echarts.init(document.getElementById(idd)); + var option1 = { + tooltip: {}, + + visualMap: { + show: false, + dimension: 2, + min: -1, + max: 1, + inRange: { + color: ['#313695', '#4575b4', '#74add1', '#abd9e9', '#e0f3f8', '#ffffbf', '#fee090', '#fdae61', '#f46d43', '#d73027', '#a50026'] + } + }, + xAxis3D: { + type: 'value' + }, + yAxis3D: { + type: 'value' + }, + zAxis3D: { + type: 'value', + max: 1, + splitNumber: 2 + }, + grid3D: { + viewControl: { + // projection: 'orthographic' + }, + boxHeight: 40 + }, + series: [{ + type: 'surface', + wireframe: { + show: false + }, + shading: 'color', + equation: { + x: { + step: 0.05, + min: -3, + max: 3, + }, + y: { + step: 0.05, + min: -3, + max: 3, + }, + z: function (x, y) { + return Math.sin(x * x + y * y) * x / 3.14; + } + } + }] + }; + if(scope.data.length === 0){ + myChart.setOption(option_nodata);}else{ + myChart.setOption(option1); + myChart.on('click', function (params) { + // 点击è”动 + scope.build_search(params); + }); + } + } + if(scope.panel.chart === 'earth') { + myChart = echarts.init(document.getElementById(idd)); + var option = { + backgroundColor: '#000', + globe: { + baseTexture: 'vendor/echarts/data-1491890179041-Hkj-elqpe.jpg', + heightTexture: 'vendor/echarts/data-1491889019097-rJQYikcpl.jpg', + + displacementScale: 0.1, + + shading: 'lambert', + + environment: 'vendor/echarts/data-1491837999815-H1_44Qtal.jpg', + + light: { + ambient: { + intensity: 0.1 + }, + main: { + intensity: 1.5 + } + }, + + layers: [{ + type: 'blend', + blendTo: 'emission', + texture: 'vendor/echarts/data-1491890291849-rJ2uee5ag.jpg' + }, { + type: 'overlay', + texture: 'vendor/echarts/data-1491890092270-BJEhJg96l.png', + shading: 'lambert', + distance: 5 + }] + }, + series: [] + }; + if(scope.data.length === 0){ + myChart.setOption(option_nodata);}else{ + myChart.setOption(option); + myChart.on('click', function (params) { + // 点击è”动 + scope.build_search(params); + }); + } + } + + + if(scope.panel.chart === 'earth1') { + myChart = echarts.init(document.getElementById(idd)); + // $.getJSON("vendor/echarts/data-1491887968120-rJODPy9ae.json", function (data) { + + var data2 = scope.data.filter(function (dataItem) { + return dataItem[2] > 0; + }).map(function (dataItem) { + return [dataItem[0], dataItem[1], Math.sqrt(dataItem[2])]; + }); + + var option11 = { + + globe: { + baseTexture: 'vendor/echarts/data-1491890179041-Hkj-elqpe.jpg', + heightTexture: 'vendor/echarts/data-1491889019097-rJQYikcpl.jpg', + + displacementScale: 0.1, + + shading: 'lambert', + + environment: 'vendor/echarts/data-1491837999815-H1_44Qtal.jpg', + + light: { + ambient: { + intensity: 0.1 + }, + main: { + intensity: 1.5 + } + }, + + layers: [{ + type: 'blend', + blendTo: 'emission', + texture: 'vendor/echarts/data-1491890291849-rJ2uee5ag.jpg' + }, { + type: 'overlay', + texture: 'vendor/echarts/data-1491890092270-BJEhJg96l.png', + shading: 'lambert', + distance: 5 + }] + }, + visualMap: { + max: 40, + calculable: true, + realtime: false, + inRange: { + color: ['#313695', '#4575b4', '#74add1', '#abd9e9', '#e0f3f8', '#ffffbf', '#fee090', '#fdae61', '#f46d43', '#d73027', '#a50026'] + }, + textStyle: { + color: '#fff' + }, + controller: { + inRange: { + color: ['#313695', '#4575b4', '#74add1', '#abd9e9', '#e0f3f8', '#ffffbf', '#fee090', '#fdae61', '#f46d43', '#d73027', '#a50026'] + } + }, + outOfRange: { + colorAlpha: 0 + } + }, + series: [{ + type: 'bar3D', + coordinateSystem: 'globe', + data: data2, + barSize: 0.6, + minHeight: 2, + maxHeight: 20, + silent: true, + itemStyle: { + color: 'orange' + } + }] + }; + + myChart.setOption(option11); + // }) + } + // if(scope.panel.chart === 'world') { + // myChart = echarts.init(document.getElementById(idd)); + // $.getJSON("vendor/echarts/data-1491887968120-rJODPy9ae.json", function () { + // + // var data3 = scope.data.filter(function (dataItem) { + // return dataItem[2] > 0; + // }).map(function (dataItem) { + // return [dataItem[0], dataItem[1], Math.sqrt(dataItem[2])]; + // }); + // + // var option5 = { + // + // backgroundColor: '#cdcfd5', + // geo3D: { + // map: 'world', + // shading: 'lambert', + // + // lambertMaterial: { + // baseTexture: 'vendor/echarts/data-1491896059428-B1QbPbq6e.jpg', + // textureTiling: 20 + // }, + // + // postEffect: { + // enable: true, + // SSAO: { + // enable: true, + // radius: 3, + // quality: 'high' + // } + // }, + // groundPlane: { + // show: true + // }, + // light: { + // main: { + // intensity: 1, + // shadow: true, + // shadowQuality: 'high', + // alpha: 30 + // }, + // ambient: { + // intensity: 0 + // }, + // ambientCubemap: { + // texture: 'vendor/echarts/data-1491896094618-H1DmP-5px.hdr', + // exposure: 2, + // diffuseIntensity: 0.3 + // } + // }, + // viewControl: { + // distance: 50 + // }, + // + // boxHeight: 0.5 + // }, + // visualMap: { + // max: 40, + // calculable: true, + // realtime: false, + // inRange: { + // color: ['#313695', '#4575b4', '#74add1', '#abd9e9', '#e0f3f8', '#ffffbf', '#fee090', '#fdae61', '#f46d43', '#d73027', '#a50026'] + // }, + // outOfRange: { + // colorAlpha: 0 + // } + // }, + // series: [{ + // type: 'bar3D', + // coordinateSystem: 'geo3D', + // shading: 'lambert', + // data: data3, + // barSize: 0.1, + // minHeight: 0.2, + // maxHeight: 10, + // silent: true, + // itemStyle: { + // color: 'orange' + // // opacity: 0.8 + // } + // }] + // }; + // + // myChart.setOption(option5); + // }); + // } + + + + // Populate legend + + + } catch(e) { + elem.text(e); + } + }); + } + + + + + + } + }; + }); + +}); diff --git a/src/app/panels/histobar/editor.html b/src/app/panels/histobar/editor.html new file mode 100644 index 000000000..d0e8e3e9a --- /dev/null +++ b/src/app/panels/histobar/editor.html @@ -0,0 +1,115 @@ +
+
+ + + + +
+
+ + +
+
+ + +
+
+ + +
+ + +
+ + +
+
+ In {{panel.mode}} mode the configured field must be a numeric type. +
+
+ + +
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+ +
+ + +
+
+ + +
+ + +
+ + +
+ + + +
+ + + +
Chart Settings
+ + + + +
+ + +
+ +
+
+ +
+
+ + +
+
+ + +
+ +
+ +
Tooltip Settings
+
+
+ + +
+
+ + +
+
+
+
Linkage Effective
+
+ +
+ +
diff --git a/src/app/panels/histobar/interval.js b/src/app/panels/histobar/interval.js new file mode 100644 index 000000000..673371fcf --- /dev/null +++ b/src/app/panels/histobar/interval.js @@ -0,0 +1,57 @@ +define([ + 'kbn' +], +function (kbn) { + 'use strict'; + + /** + * manages the interval logic + * @param {[type]} interval_string An interval string in the format '1m', '1y', etc + */ + function Interval(interval_string) { + this.string = interval_string; + + var info = kbn.describe_interval(interval_string); + this.type = info.type; + this.ms = info.sec * 1000 * info.count; + + // does the length of the interval change based on the current time? + if (this.type === 'y' || this.type === 'M') { + // we will just modify this time object rather that create a new one constantly + this.get = this.get_complex; + this.date = new Date(0); + } else { + this.get = this.get_simple; + } + } + + Interval.prototype = { + toString: function () { + return this.string; + }, + after: function(current_ms) { + return this.get(current_ms, 1); + }, + before: function (current_ms) { + return this.get(current_ms, -1); + }, + get_complex: function (current, delta) { + this.date.setTime(current); + switch(this.type) { + case 'M': + this.date.setUTCMonth(this.date.getUTCMonth() + delta); + break; + case 'y': + this.date.setUTCFullYear(this.date.getUTCFullYear() + delta); + break; + } + return this.date.getTime(); + }, + get_simple: function (current, delta) { + return current + (delta * this.ms); + } + }; + + return Interval; + +}); \ No newline at end of file diff --git a/src/app/panels/histobar/module.html b/src/app/panels/histobar/module.html new file mode 100644 index 000000000..06f95e0a0 --- /dev/null +++ b/src/app/panels/histobar/module.html @@ -0,0 +1,133 @@ +
+ + +
+ +
+ + + View + + +
+ + + + + + + + + + + + + +
+ +
+
+ + + + + + +
{{term.label}}{{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}
+ + +
+ {{term.label}} ({{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}) +

+ +
+
{{data.length - 2}}
+ +
+ +
+ + + + + + +
{{term.label}}{{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}
+
+ +
+ +
+ + + + + + +
{{term.label}}{{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}
+ + +
+ {{term.label}} ({{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}) +

+ +
+ + + + + + +
+
+
diff --git a/src/app/panels/histobar/module.js b/src/app/panels/histobar/module.js new file mode 100644 index 000000000..42497eecd --- /dev/null +++ b/src/app/panels/histobar/module.js @@ -0,0 +1,701 @@ +/* + + ## Histogram + + ### Parameters + * auto_int :: Auto calculate data point interval? + * resolution :: If auto_int is enables, shoot for this many data points, rounding to + sane intervals + * interval :: Datapoint interval in elasticsearch date math format (eg 1d, 1w, 1y, 5y) + * fill :: Only applies to line charts. Level of area shading from 0-10 + * linewidth :: Only applies to line charts. How thick the line should be in pixels + While the editor only exposes 0-10, this can be any numeric value. + Set to 0 and you'll get something like a scatter plot + * timezone :: This isn't totally functional yet. Currently only supports browser and utc. + browser will adjust the x-axis labels to match the timezone of the user's + browser + * spyable :: Dislay the 'eye' icon that show the last elasticsearch query + * zoomlinks :: Show the zoom links? + * bars :: Show bars in the chart + * stack :: Stack multiple queries. This generally a crappy way to represent things. + You probably should just use a line chart without histobar + * points :: Should circles at the data points on the chart + * lines :: Line chart? Sweet. + * legend :: Show the legend? + * x-axis :: Show x-axis labels and grid lines + * y-axis :: Show y-axis labels and grid lines + * interactive :: Allow drag to select time range + +*/ +define([ + 'angular', + 'app', + 'jquery', + 'underscore', + 'kbn', + 'moment', + './timeSeries', + 'echarts' +], +function (angular, app, $, _, kbn, moment, timeSeries) { + 'use strict'; + var module = angular.module('kibana.panels.histobar', []); + app.useModule(module); + + module.controller('histobar', function($scope, $q, querySrv, dashboard, filterSrv) { + var _d; + $scope.panelMeta = { + + editorTabs : [ + { + title:'Queries', + src:'app/partials/querySelect.html' + } + ], + status : "Stable", + description : "A bucketed time series chart of the current query, including all applied time and non-time filters, when used in count mode. Uses Solr’s facet.range query parameters. In values mode, it plots the value of a specific field over time, and allows the user to group field values by a second field." + }; + + // Set and populate defaults + _d = { + mode: 'value', + queries: { + mode: 'all', + ids: [], + query: '*:*', + custom: '' + }, + max_rows: 100000, // maximum number of rows returned from Solr (also use this for group.limit to simplify UI setting) + reverse: 0, + segment: 4, + + threshold_first: 300, + threshold_second: 400, + threshold_third: 3000, + group_field: null, + auto_int: true, + linkage_id:'a', + defaulttimestamp:true, + display:'block', + icon:"icon-caret-down", + area:false, + total_first: '%', + fontsize: 12, + isEN:false, + field_color: '#2ce41b', + resolution: 100, + value_sort: 'rs_timestamp', + interval: '5m', + intervals: ['auto', '1s', '1m', '5m', '10m', '30m', '1h', '3h', '12h', '1d', '1w', '1M', '1y'], + fill: 0, + linewidth: 3, + chart: 'histobar', + chartColors: ['#f48a52', '#f4d352', '#ccf452', '#8cf452', '#3cee2b', '#f467d8', '#1a93f9', '#2fd7ee'], + timezone: 'browser', // browser, utc or a standard timezone + spyable: true, + linkage: false, + zoomlinks: true, + bars: true, + average: false, + label: true, + points: false, + lines: false, + lines_smooth: false, // Enable 'smooth line' mode by removing zero values from the plot. + legend: true, + 'x-axis': true, + 'y-axis': true, + percentage: false, + interactive: true, + options: false, + show_queries: true, + tooltip: { + value_type: 'cumulative', + query_as_alias: false + } + }; + _.defaults($scope.panel,_d); + + $scope.init = function() { + // Hide view options by default + $scope.options = false; + $scope.$on('refresh',function(){ + $scope.get_data(); + }); + + $scope.get_data(); + + }; + + $scope.set_interval = function(interval) { + if(interval !== 'auto') { + $scope.panel.auto_int = false; + $scope.panel.interval = interval; + } else { + $scope.panel.auto_int = true; + } + }; + + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; + + $scope.interval_label = function(interval) { + return $scope.panel.auto_int && interval === $scope.panel.interval ? interval+" (auto)" : interval; + }; + + /** + * The time range effecting the panel + * @return {[type]} [description] + */ + $scope.get_time_range = function () { + var range = $scope.range = filterSrv.timeRange('min'); + return range; + }; + + $scope.get_interval = function () { + var interval = $scope.panel.interval, + range; + if ($scope.panel.auto_int) { + range = $scope.get_time_range(); + if (range) { + interval = kbn.secondsToHms( + kbn.calculate_interval(range.from, range.to, $scope.panel.resolution, 0) / 1000 + ); + } + } + $scope.panel.interval = interval || '10m'; + return $scope.panel.interval; + }; + + /** + * Fetch the data for a chunk of a queries results. Multiple segments occur when several indicies + * need to be consulted (like timestamped logstash indicies) + * + * The results of this function are stored on the scope's data property. This property will be an + * array of objects with the properties info, time_series, and hits. These objects are used in the + * render_panel function to create the historgram. + * + * !!! Solr does not need to fetch the data in chunk because it uses a facet search and retrieve + * !!! all events from a single query. + * + * @param {number} segment The segment count, (0 based) + * @param {number} query_id The id of the query, generated on the first run and passed back when + * this call is made recursively for more segments + */ + $scope.get_data = function(segment, query_id) { + if(($scope.panel.linkage_id === dashboard.current.linkage_id)||dashboard.current.enable_linkage){ + if (_.isUndefined(segment)) { + segment = 0; + } + delete $scope.panel.error; + + // Make sure we have everything for the request to complete + if (dashboard.indices.length === 0) { + return; + } + var _range = $scope.get_time_range(); + var _interval = $scope.get_interval(_range); + + if ($scope.panel.auto_int) { + $scope.panel.interval = kbn.secondsToHms( + kbn.calculate_interval(_range.from, _range.to, $scope.panel.resolution, 0) / 1000); + } + + $scope.panelMeta.loading = true; + + // Solr + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + var request = $scope.sjs.Request().indices(dashboard.indices[segment]); + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + + + $scope.panel.queries.query = ""; + // Build the query + _.each($scope.panel.queries.ids, function (id) { + var query = $scope.sjs.FilteredQuery( + querySrv.getEjsObj(id), + filterSrv.getBoolFilter(filterSrv.ids) + ); + + var facet = $scope.sjs.DateHistogramFacet(id); + if ($scope.panel.mode === 'count' || $scope.panel.mode === 'counts') { + facet = facet.field(filterSrv.getTimeField()); + } else { + if (_.isNull($scope.panel.value_field)) { + $scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified"; + return; + } + facet = facet.keyField(filterSrv.getTimeField()).valueField($scope.panel.value_field); + } + facet = facet.interval(_interval).facetFilter($scope.sjs.QueryFilter(query)); + request = request.facet(facet).size(0); + + }); + + // Populate the inspector panel + $scope.populate_modal(request); + + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + } + if (!$scope.panel.defaulttimestamp) { + fq = fq.replace(filterSrv.getTimeField(), $scope.panel.value_sort); + } + var time_field = $scope.panel.defaulttimestamp ? filterSrv.getTimeField() : $scope.panel.value_sort; + var start_time = filterSrv.getStartTime(); + var end_time = filterSrv.getEndTime(); + + // facet.range.end does NOT accept * as a value, need to convert it to NOW + if (end_time === '*') { + end_time = 'NOW'; + } + + var wt_json = '&wt=json'; + var sort_s = '&sort=' + $scope.panel.value_sort + '%20asc'; + var rows_limit = '&rows=0'; // for histogram, we do not need the actual response doc, so set rows=0 + var facet_gap = $scope.sjs.convertFacetGap($scope.panel.interval); + var facet = '&facet=true' + + '&facet.range=' + time_field + + '&facet.range.start=' + start_time + + '&facet.range.end=' + end_time + + '&facet.range.gap=' + facet_gap; + var values_mode_query = ''; + + // For mode = value + if ($scope.panel.mode === 'values' || $scope.panel.mode === 'value') { + if (!$scope.panel.value_field) { + $scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified"; + return; + } + values_mode_query = '&fl=' + time_field + ' ' + $scope.panel.value_field; + + rows_limit = '&rows=' + $scope.panel.max_rows; + facet = ''; + + // if Group By Field is specified + if ($scope.panel.group_field) { + values_mode_query += '&group=true&group.field=' + $scope.panel.group_field + '&group.limit=' + $scope.panel.max_rows; + } + } + + var mypromises = []; + if ($scope.panel.mode === 'value' || $scope.panel.mode === 'counts') { + var arr_id = [0]; + _.each(arr_id, function () { + var temp_q = 'q=' + $scope.panel.value_field + '%3A%5B' + '*' + '%20TO%20' + '*' + '%5D' + wt_json + sort_s + rows_limit + fq + facet + values_mode_query; + + $scope.panel.queries.query += temp_q + "\n"; + if ($scope.panel.queries.custom !== null) { + request = request.setQuery(temp_q + $scope.panel.queries.custom); + } else { + request = request.setQuery(temp_q); + } + mypromises.push(request.doSearch()); + }); + } + $scope.data = []; + + if (dashboard.current.services.query.ids.length >= 1) { + $q.all(mypromises).then(function (results) { + $scope.panelMeta.loading = false; + if (segment === 0) { + $scope.hits = 0; + $scope.data = []; + query_id = $scope.query_id = new Date().getTime(); + } + // Convert facet ids to numbers + // var facetIds = _.map(_.keys(results.facets),function(k){return parseInt(k, 10);}); + //var facetIds = [0]; // Need to fix this + + // Make sure we're still on the same query/queries + // TODO: We probably DON'T NEED THIS unless we have to support multiple queries in query module. + // if ($scope.query_id === query_id && _.difference(facetIds, $scope.panel.queries.ids).length === 0) { + var i = 0, + time_series, + hits; + + _.each(arr_id, function (id, index) { + // Check for error and abort if found + if (!(_.isUndefined(results[index].error))) { + $scope.panel.error = $scope.parse_error(results[index].error.msg); + return; + } + // we need to initialize the data variable on the first run, + // and when we are working on the first segment of the data. + if (_.isUndefined($scope.data[i]) || segment === 0) { + time_series = new timeSeries.ZeroFilled({ + interval: _interval, + start_date: _range && _range.from, + end_date: _range && _range.to, + fill_style: 'minimal' + }); + hits = 0; + } else { + time_series = $scope.data[i].time_series; + // Bug fix for wrong event count: + // Solr don't need to accumulate hits count since it can get total count from facet query. + // Therefore, I need to set hits and $scope.hits to zero. + // hits = $scope.data[i].hits; + hits = 0; + $scope.hits = 0; + } + + $scope.data[i] = results[index].response.docs; + + + i++; + }); + + // Tell the histogram directive to render. + $scope.$emit('render'); + // } + }); + } + + } + }; + + // function $scope.zoom + // factor :: Zoom factor, so 0.5 = cuts timespan in half, 2 doubles timespan + $scope.zoom = function(factor) { + var _range = filterSrv.timeRange('min'); + var _timespan = (_range.to.valueOf() - _range.from.valueOf()); + var _center = _range.to.valueOf() - _timespan/2; + + var _to = (_center + (_timespan*factor)/2); + var _from = (_center - (_timespan*factor)/2); + + // If we're not already looking into the future, don't. + if(_to > Date.now() && _range.to < Date.now()) { + var _offset = _to - Date.now(); + _from = _from - _offset; + _to = Date.now(); + } + + var time_field = filterSrv.getTimeField(); + if(factor > 1) { + filterSrv.removeByType('time'); + } + + filterSrv.set({ + type:'time', + from:moment.utc(_from).toDate(), + to:moment.utc(_to).toDate(), + field:time_field + }); + + dashboard.refresh(); + }; + + // I really don't like this function, too much dom manip. Break out into directive? + $scope.populate_modal = function(request) { + $scope.inspector = angular.toJson(JSON.parse(request.toString()),true); + }; + + $scope.set_refresh = function (state) { + $scope.refresh = state; + }; + + $scope.close_edit = function() { + if($scope.refresh) { + $scope.get_data(); + } + $scope.refresh = false; + $scope.$emit('render'); + }; + + $scope.render = function() { + $scope.$emit('render'); + }; + + }); + + module.directive('histobarChart', function(querySrv,dashboard,filterSrv) { + return { + restrict: 'A', + link: function(scope, elem) { + var myChart; + // Receive render events + scope.$on('render',function(){ + render_panel(); + }); + + // Re-render if the window is resized + angular.element(window).bind('resize', function(){ + render_panel(); + }); + + // Function for rendering panel + function render_panel() { + var chartData; + var colors = []; + + // IE doesn't work without this + elem.css({height:scope.panel.height||scope.row.height}); + + // Make a clone we can operate on. + + chartData = _.clone(scope.data); + chartData = scope.panel.missing ? chartData : + _.without(chartData,_.findWhere(chartData,{meta:'missing'})); + chartData = scope.panel.other ? chartData : + _.without(chartData,_.findWhere(chartData,{meta:'other'})); + + if (filterSrv.idsByTypeAndField('terms',scope.panel.field).length > 0) { + colors.push(scope.panel.lastColor); + } else { + colors = scope.panel.chartColors; + } + var selecttime = []; + var rs_timestamp = []; + var valuedata= []; + var secondtime ; + var maxdata= 0; + var sum_data = 0; + var sum_normal = 0; + var sum_risk = 0; + var sum_warning = 0; + + + Date.prototype.pattern = function (fmt) { + var o = { + "M+" : this.getMonth() + 1, //月份 + "d+" : this.getDate(), //æ—¥ + "h+" : this.getHours(), //å°æ—¶ + "H+" : this.getHours(), //å°æ—¶ + "m+" : this.getMinutes(), //分 + "s+" : this.getSeconds(), //ç§’ + "q+" : Math.floor((this.getMonth() + 3) / 3), //季度 + "S" : this.getMilliseconds() //毫秒 + }; + var week = { + "0" : "/u65e5", + "1" : "/u4e00", + "2" : "/u4e8c", + "3" : "/u4e09", + "4" : "/u56db", + "5" : "/u4e94", + "6" : "/u516d" + }; + if (/(y+)/.test(fmt)) { + fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length)); + } + if (/(E+)/.test(fmt)) { + fmt = fmt.replace(RegExp.$1, ((RegExp.$1.length > 1) ? (RegExp.$1.length > 2 ? "/u661f/u671f" : "/u5468") : "") + week[this.getDay() + ""]); + } + for (var k in o) { + if (new RegExp("(" + k + ")").test(fmt)) { + fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); + } + } + return fmt; + }; + + for (var i =0;iscope.panel.threshold_second){ + sum_risk++; + // valuedata[i] ={name:"Risk",value:chartData[0][i][scope.panel.value_field],itemStyle:{normal:{color:'#c55249'}}}; + }else if(chartData[0][i][scope.panel.value_field]'+scope.panel.threshold_second+" "+sum_risk+'%)', + color: '#ec4653' + }], + outOfRange: { + color: '#999' + } + }, + calculable : true, + xAxis : [ + { + type : 'category', + axisLine: {onZero: true}, + axisLabel:{ + textStyle:{ + color:labelcolor?'#DCDCDC':'#696969' + } + }, + data : rs_timestamp + } + ], + yAxis : [ + { + type : 'value', + nameTextStyle:{ + color:labelcolor?'#DCDCDC':'#696969' + }, + axisLine:{ + lineStyle:{ + color:'#46474C' + } + }, + splitLine:{ + lineStyle:{ + color:['#46474C'] + } + }, + axisLabel:{ + textStyle:{ + color:labelcolor?'#DCDCDC':'#696969' + } + } + } + ], + series : [ + { + name:scope.panel.value_field, + type:scope.panel.bars?'bar':'line', + data:valuedata, + smooth: true, + areaStyle: scope.panel.area?{normal: {opacity:0.6}}:'', + markPoint : { + data : [ + {type : 'max', name: scope.panel.isEN?'Max':'最大值'}, + {type : 'min', name: scope.panel.isEN?'Min':'最å°å€¼'} + ] + }, + markLine : scope.panel.average?{ + label:{ + normal:{ + show:true, + position:'start' + } + }, + lineStyle:{ + normal:{ + color:scope.panel.field_color + } + }, + data : [ + {type : 'average', name:scope.panel.isEN?'Average':'å¹³å‡å€¼'} + ] + }:'' + } + ] + }; + myChart.setOption(option); + myChart.on('datazoom', function (params) { + if (scope.panel.linkage) { + filterSrv.set({ + type: 'time', + // from : moment.utc(ranges.xaxis.from), + // to : moment.utc(ranges.xaxis.to), + from: moment.utc(selecttime[params.batch[0].startValue]).toDate(), + to: moment.utc(selecttime[params.batch[0].endValue]).toDate(), + field: filterSrv.getTimeField() + }); + dashboard.current.linkage_id = scope.panel.linkage_id; + dashboard.current.enable_linkage = false; + dashboard.refresh(); + } + }); + } + } + + } + }; + }); + +}); diff --git a/src/app/panels/histobar/timeSeries.js b/src/app/panels/histobar/timeSeries.js new file mode 100644 index 000000000..96054fa7d --- /dev/null +++ b/src/app/panels/histobar/timeSeries.js @@ -0,0 +1,179 @@ +define([ + 'underscore', + './interval' +], +function (_, Interval) { + 'use strict'; + + var ts = {}; + + // map compatable parseInt + function base10Int(val) { + return parseInt(val, 10); + } + + // trim the ms off of a time, but return it with empty ms. + function getDatesTime(date) { + return Math.floor(date.getTime() / 1000)*1000; + } + + /** + * Certain graphs require 0 entries to be specified for them to render + * properly (like the line graph). So with this we will caluclate all of + * the expected time measurements, and fill the missing ones in with 0 + * @param {object} opts An object specifying some/all of the options + * + * OPTIONS: + * @opt {string} interval The interval notion describing the expected spacing between + * each data point. + * @opt {date} start_date (optional) The start point for the time series, setting this and the + * end_date will ensure that the series streches to resemble the entire + * expected result + * @opt {date} end_date (optional) The end point for the time series, see start_date + * @opt {string} fill_style Either "minimal", or "all" describing the strategy used to zero-fill + * the series. + */ + ts.ZeroFilled = function (opts) { + opts = _.defaults(opts, { + interval: '10m', + start_date: null, + end_date: null, + fill_style: 'minimal' + }); + + // the expected differenece between readings. + this.interval = new Interval(opts.interval); + + // will keep all values here, keyed by their time + this._data = {}; + this.start_time = opts.start_date && getDatesTime(opts.start_date); + this.end_time = opts.end_date && getDatesTime(opts.end_date); + this.opts = opts; + }; + + /** + * Add a row + * @param {int} time The time for the value, in + * @param {any} value The value at this time + */ + ts.ZeroFilled.prototype.addValue = function (time, value) { + if (time instanceof Date) { + time = getDatesTime(time); + } else { + time = base10Int(time); + } + if (!isNaN(time)) { + this._data[time] = (_.isUndefined(value) ? 0 : value); + } + this._cached_times = null; + }; + + /** + * Get an array of the times that have been explicitly set in the series + * @param {array} include (optional) list of timestamps to include in the response + * @return {array} An array of integer times. + */ + ts.ZeroFilled.prototype.getOrderedTimes = function (include) { + var times = _.map(_.keys(this._data), base10Int); + if (_.isArray(include)) { + times = times.concat(include); + } + return _.uniq(times.sort(function (a, b) { + // decending numeric sort + return a - b; + }), true); + }; + + /** + * return the rows in the format: + * [ [time, value], [time, value], ... ] + * + * Heavy lifting is done by _get(Min|All)FlotPairs() + * @param {array} required_times An array of timestamps that must be in the resulting pairs + * @return {array} + */ + ts.ZeroFilled.prototype.getFlotPairs = function (required_times) { + var times = this.getOrderedTimes(required_times), + strategy, + pairs; + + if(this.opts.fill_style === 'all') { + strategy = this._getAllFlotPairs; + } else { + strategy = this._getMinFlotPairs; + } + + pairs = _.reduce( + times, // what + strategy, // how + [], // where + this // context + ); + + // if the first or last pair is inside either the start or end time, + // add those times to the series with null values so the graph will stretch to contain them. + if (this.start_time && (pairs.length === 0 || pairs[0][0] > this.start_time)) { + pairs.unshift([this.start_time, null]); + } + if (this.end_time && (pairs.length === 0 || pairs[pairs.length - 1][0] < this.end_time)) { + pairs.push([this.end_time, null]); + } + + return pairs; + }; + + /** + * ** called as a reduce stragegy in getFlotPairs() ** + * Fill zero's on either side of the current time, unless there is already a measurement there or + * we are looking at an edge. + * @return {array} An array of points to plot with flot + */ + ts.ZeroFilled.prototype._getMinFlotPairs = function (result, time, i, times) { + var next, expected_next, prev, expected_prev; + + // check for previous measurement + if (i > 0) { + prev = times[i - 1]; + expected_prev = this.interval.before(time); + if (prev < expected_prev) { + result.push([expected_prev, 0]); + } + } + + // add the current time + result.push([ time, this._data[time] || 0 ]); + + // check for next measurement + if (times.length > i) { + next = times[i + 1]; + expected_next = this.interval.after(time); + if (next > expected_next) { + result.push([expected_next, 0]); + } + } + + return result; + }; + + /** + * ** called as a reduce stragegy in getFlotPairs() ** + * Fill zero's to the right of each time, until the next measurement is reached or we are at the + * last measurement + * @return {array} An array of points to plot with flot + */ + ts.ZeroFilled.prototype._getAllFlotPairs = function (result, time, i, times) { + var next, expected_next; + + result.push([ times[i], this._data[times[i]] || 0 ]); + next = times[i + 1]; + expected_next = this.interval.after(time); + for(; times.length > i && next > expected_next; expected_next = this.interval.after(expected_next)) { + result.push([expected_next, 0]); + } + + return result; + }; + + + return ts; +}); \ No newline at end of file diff --git a/src/app/panels/histogram/editor.html b/src/app/panels/histogram/editor.html old mode 100755 new mode 100644 index e63332589..536e7440d --- a/src/app/panels/histogram/editor.html +++ b/src/app/panels/histogram/editor.html @@ -3,31 +3,56 @@ - +
-
+
-
+
+ + +
+
+ In {{panel.mode}} mode the configured field must be a numeric type. +
+
-
- In {{panel.mode}} mode the configured field must be a numeric type. +
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
-
-
+
-
- - -
Zoom Out |  - + - {{series.info.alias}} ({{dashboard.numberWithCommas(series.hits)}}) + {{series.info.alias.substring(0,series.info.alias.length-2)}} ({{series.hits}}{{series.info.alias.substr(-2)}}) - {{panel.value_field}} {{panel.mode}} per {{panel.interval}} | ({{dashboard.numberWithCommas(hits)}} hits) | Time correction : {{panel.timezone}} +
-
+ - +
\ No newline at end of file +
+
+
+
diff --git a/src/app/panels/histogram/module.js b/src/app/panels/histogram/module.js old mode 100755 new mode 100644 index 91bf255a8..46ba16be2 --- a/src/app/panels/histogram/module.js +++ b/src/app/panels/histogram/module.js @@ -50,16 +50,9 @@ function (angular, app, $, _, kbn, moment, timeSeries) { var module = angular.module('kibana.panels.histogram', []); app.useModule(module); - module.controller('histogram', function($scope, $q, $timeout, timer, querySrv, dashboard, filterSrv) { + module.controller('histogram', function($scope, $q, querySrv, dashboard, filterSrv) { $scope.panelMeta = { - modals : [ - { - description: "Inspect", - icon: "icon-info-sign", - partial: "app/partials/inspector.html", - show: $scope.panel.spyable - } - ], + editorTabs : [ { title:'Queries', @@ -80,9 +73,13 @@ function (angular, app, $, _, kbn, moment, timeSeries) { custom : '' }, max_rows : 100000, // maximum number of rows returned from Solr (also use this for group.limit to simplify UI setting) - value_field : null, + reverse :0, + segment :3, + threshold_first:1000, + threshold_second:2000, + threshold_third:3000, + value_field : null, group_field : null, - sum_value : false, auto_int : true, resolution : 100, interval : '5m', @@ -94,7 +91,10 @@ function (angular, app, $, _, kbn, moment, timeSeries) { zoomlinks : true, bars : true, stack : true, + linkage_id:'a', points : false, + display:'block', + icon:"icon-caret-down", lines : false, lines_smooth: false, // Enable 'smooth line' mode by removing zero values from the plot. legend : true, @@ -103,14 +103,10 @@ function (angular, app, $, _, kbn, moment, timeSeries) { percentage : false, interactive : true, options : true, - show_queries: true, + show_queries:true, tooltip : { value_type: 'cumulative', query_as_alias: false - }, - refresh: { - enable: false, - interval: 2 } }; @@ -119,40 +115,12 @@ function (angular, app, $, _, kbn, moment, timeSeries) { $scope.init = function() { // Hide view options by default $scope.options = false; - - // Start refresh timer if enabled - if ($scope.panel.refresh.enable) { - $scope.set_timer($scope.panel.refresh.interval); - } - $scope.$on('refresh',function(){ $scope.get_data(); }); $scope.get_data(); - }; - $scope.set_timer = function(refresh_interval) { - $scope.panel.refresh.interval = refresh_interval; - if (_.isNumber($scope.panel.refresh.interval)) { - timer.cancel($scope.refresh_timer); - $scope.realtime(); - } else { - timer.cancel($scope.refresh_timer); - } - }; - - $scope.realtime = function() { - if ($scope.panel.refresh.enable) { - timer.cancel($scope.refresh_timer); - - $scope.refresh_timer = timer.register($timeout(function() { - $scope.realtime(); - $scope.get_data(); - }, $scope.panel.refresh.interval*1000)); - } else { - timer.cancel($scope.refresh_timer); - } }; $scope.set_interval = function(interval) { @@ -164,6 +132,18 @@ function (angular, app, $, _, kbn, moment, timeSeries) { } }; + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; + $scope.interval_label = function(interval) { return $scope.panel.auto_int && interval === $scope.panel.interval ? interval+" (auto)" : interval; }; @@ -208,249 +188,307 @@ function (angular, app, $, _, kbn, moment, timeSeries) { * this call is made recursively for more segments */ $scope.get_data = function(segment, query_id) { - if (_.isUndefined(segment)) { - segment = 0; - } - delete $scope.panel.error; + if(($scope.panel.linkage_id === dashboard.current.linkage_id)||dashboard.current.enable_linkage){ - // Make sure we have everything for the request to complete - if(dashboard.indices.length === 0) { - return; - } - var _range = $scope.get_time_range(); - var _interval = $scope.get_interval(_range); + if (_.isUndefined(segment)) { + segment = 0; + } + delete $scope.panel.error; - if ($scope.panel.auto_int) { - $scope.panel.interval = kbn.secondsToHms( - kbn.calculate_interval(_range.from,_range.to,$scope.panel.resolution,0)/1000); - } + // Make sure we have everything for the request to complete + if (dashboard.indices.length === 0) { + return; + } + var _range = $scope.get_time_range(); + var _interval = $scope.get_interval(_range); - $scope.panelMeta.loading = true; + if ($scope.panel.auto_int) { + $scope.panel.interval = kbn.secondsToHms( + kbn.calculate_interval(_range.from, _range.to, $scope.panel.resolution, 0) / 1000); + } - // Solr - $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + $scope.panelMeta.loading = true; - var request = $scope.sjs.Request().indices(dashboard.indices[segment]); - $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); - + // Solr + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); - $scope.panel.queries.query = ""; - // Build the query - _.each($scope.panel.queries.ids, function(id) { - var query = $scope.sjs.FilteredQuery( - querySrv.getEjsObj(id), - filterSrv.getBoolFilter(filterSrv.ids) - ); + var request = $scope.sjs.Request().indices(dashboard.indices[segment]); + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); - var facet = $scope.sjs.DateHistogramFacet(id); - if($scope.panel.mode === 'count') { - facet = facet.field(filterSrv.getTimeField()); - } else { - if(_.isNull($scope.panel.value_field)) { - $scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified"; - return; - } - facet = facet.keyField(filterSrv.getTimeField()).valueField($scope.panel.value_field); - } - facet = facet.interval(_interval).facetFilter($scope.sjs.QueryFilter(query)); - request = request.facet(facet).size(0); - }); + $scope.panel.queries.query = ""; + // Build the query + _.each($scope.panel.queries.ids, function (id) { + var query = $scope.sjs.FilteredQuery( + querySrv.getEjsObj(id), + filterSrv.getBoolFilter(filterSrv.ids) + ); - // Populate the inspector panel - $scope.populate_modal(request); + var facet = $scope.sjs.DateHistogramFacet(id); + if ($scope.panel.mode === 'count' || $scope.panel.mode === 'counts') { + facet = facet.field(filterSrv.getTimeField()); + } else { + if (_.isNull($scope.panel.value_field)) { + $scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified"; + return; + } + facet = facet.keyField(filterSrv.getTimeField()).valueField($scope.panel.value_field); + } + facet = facet.interval(_interval).facetFilter($scope.sjs.QueryFilter(query)); + request = request.facet(facet).size(0); - // Build Solr query - var fq = ''; - if (filterSrv.getSolrFq()) { - fq = '&' + filterSrv.getSolrFq(); - } - var time_field = filterSrv.getTimeField(); - var start_time = filterSrv.getStartTime(); - var end_time = filterSrv.getEndTime(); + }); - // facet.range.end does NOT accept * as a value, need to convert it to NOW - if (end_time === '*') { - end_time = 'NOW'; - } + // Populate the inspector panel + $scope.populate_modal(request); - var wt_json = '&wt=json'; - var rows_limit = '&rows=0'; // for histogram, we do not need the actual response doc, so set rows=0 - var facet_gap = $scope.sjs.convertFacetGap($scope.panel.interval); - var facet = '&facet=true' + - '&facet.range=' + time_field + - '&facet.range.start=' + start_time + - '&facet.range.end=' + end_time + - '&facet.range.gap=' + facet_gap; - var values_mode_query = ''; - - // For mode = value - if($scope.panel.mode === 'values') { - if (!$scope.panel.value_field) { - $scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified"; - return; + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); } + var time_field = filterSrv.getTimeField(); + var start_time = filterSrv.getStartTime(); + var end_time = filterSrv.getEndTime(); - values_mode_query = '&fl=' + time_field + ' ' + $scope.panel.value_field; - rows_limit = '&rows=' + $scope.panel.max_rows; - facet = ''; - - // if Group By Field is specified - if ($scope.panel.group_field) { - values_mode_query += '&group=true&group.field=' + $scope.panel.group_field + '&group.limit=' + $scope.panel.max_rows; + // facet.range.end does NOT accept * as a value, need to convert it to NOW + if (end_time === '*') { + end_time = 'NOW'; } - } - - var mypromises = []; - _.each($scope.panel.queries.ids, function(id) { - var temp_q = querySrv.getQuery(id) + wt_json + rows_limit + fq + facet + values_mode_query; - $scope.panel.queries.query += temp_q + "\n"; - if ($scope.panel.queries.custom !== null) { - request = request.setQuery(temp_q + $scope.panel.queries.custom); - } else { - request = request.setQuery(temp_q); - } - mypromises.push(request.doSearch()); - }); - if (dashboard.current.services.query.ids.length >= 1) { - $q.all(mypromises).then(function(results) { - $scope.panelMeta.loading = false; - if (segment === 0) { - $scope.hits = 0; - $scope.data = []; - query_id = $scope.query_id = new Date().getTime(); - } - // Convert facet ids to numbers - // var facetIds = _.map(_.keys(results.facets),function(k){return parseInt(k, 10);}); - // TODO: change this, Solr do faceting differently - // var facetIds = [0]; // Need to fix this - - // Make sure we're still on the same query/queries - // TODO: We probably DON'T NEED THIS unless we have to support multiple queries in query module. - // if ($scope.query_id === query_id && _.difference(facetIds, $scope.panel.queries.ids).length === 0) { - var i = 0, - time_series, - hits; - - _.each($scope.panel.queries.ids, function(id,index) { - // Check for error and abort if found - if (!(_.isUndefined(results[index].error))) { - $scope.panel.error = $scope.parse_error(results[index].error.msg); + var wt_json = '&wt=json'; + var rows_limit = '&rows=0'; // for histogram, we do not need the actual response doc, so set rows=0 + var facet_gap = $scope.sjs.convertFacetGap($scope.panel.interval); + var facet = '&facet=true' + + '&facet.range=' + time_field + + '&facet.range.start=' + start_time + + '&facet.range.end=' + end_time + + '&facet.range.gap=' + facet_gap; + var values_mode_query = ''; + + // For mode = value + if ($scope.panel.mode === 'values' || $scope.panel.mode === 'value') { + if (!$scope.panel.value_field) { + $scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified"; return; - } - // we need to initialize the data variable on the first run, - // and when we are working on the first segment of the data. - if (_.isUndefined($scope.data[i]) || segment === 0) { - time_series = new timeSeries.ZeroFilled({ - interval: _interval, - start_date: _range && _range.from, - end_date: _range && _range.to, - fill_style: 'minimal' - }); - hits = 0; - } else { - time_series = $scope.data[i].time_series; - // Bug fix for wrong event count: - // Solr don't need to accumulate hits count since it can get total count from facet query. - // Therefore, I need to set hits and $scope.hits to zero. - // hits = $scope.data[i].hits; - hits = 0; - $scope.hits = 0; - } + } - // Solr facet counts response is in one big array. - // So no need to get each segment like Elasticsearch does. - var entry_time, entries, entry_value; - if ($scope.panel.mode === 'count') { - // Entries from facet_ranges counts - entries = results[index].facet_counts.facet_ranges[time_field].counts; - for (var j = 0; j < entries.length; j++) { - entry_time = new Date(entries[j]).getTime(); // convert to millisec - j++; - var entry_count = entries[j]; - time_series.addValue(entry_time, entry_count); - hits += entry_count; // The series level hits counter - $scope.hits += entry_count; // Entire dataset level hits counter + values_mode_query = '&fl=' + time_field + ' ' + $scope.panel.value_field; + rows_limit = '&rows=' + $scope.panel.max_rows; + facet = ''; + + // if Group By Field is specified + if ($scope.panel.group_field) { + values_mode_query += '&group=true&group.field=' + $scope.panel.group_field + '&group.limit=' + $scope.panel.max_rows; + } + } + + var mypromises = []; + var threshold_1 = '*'; + var threshold_1_1 = '*'; + var threshold_2 = '*'; + var threshold_2_1 = '*'; + var threshold_3 = '*'; + var threshold_3_1 = '*'; + if ($scope.panel.mode === 'value' || $scope.panel.mode === 'counts') { + var arr_id = [0]; + if ($scope.panel.segment === 2) { + arr_id = [1, 0]; + threshold_1 = String($scope.panel.threshold_first - 1); + threshold_1_1 = String($scope.panel.threshold_first); + } else if ($scope.panel.segment === 3) { + arr_id = [2, 1, 0]; + threshold_1 = String($scope.panel.threshold_first - 1); + threshold_1_1 = String($scope.panel.threshold_first); + threshold_2 = String($scope.panel.threshold_second - 1); + threshold_2_1 = String($scope.panel.threshold_second); + } else if ($scope.panel.segment === 4) { + arr_id = [3, 2, 1, 0]; + threshold_1 = String($scope.panel.threshold_first - 1); + threshold_1_1 = String($scope.panel.threshold_first); + threshold_2 = String($scope.panel.threshold_second - 1); + threshold_2_1 = String($scope.panel.threshold_second); + threshold_3 = String($scope.panel.threshold_third - 1); + threshold_3_1 = String($scope.panel.threshold_third); + } + if ($scope.panel.reverse === 1) { + arr_id = arr_id.reverse(); + } + _.each(arr_id, function (id) { + var temp_q; + if (id === 0) { + //temp_q = temp_q.replace(/responseElapsed%3A%5B0%20TO%2020000%5D/,"connectElapsed%3A%5B0%20TO%2020000%5D"); + temp_q = 'q=' + $scope.panel.value_field + '%3A%5B' + 0 + '%20TO%20' + threshold_1 + '%5D' + wt_json + rows_limit + fq + facet + values_mode_query; + } + else if (id === 1) { + //temp_q = temp_q.replace(/responseElapsed%3A%5B20000%20TO%2030000%5D/,"connectElapsed%3A%5B20000%20TO%2030000%5D"); + temp_q = 'q=' + $scope.panel.value_field + '%3A%5B' + threshold_1_1 + '%20TO%20' + threshold_2 + '%5D' + wt_json + rows_limit + fq + facet + values_mode_query; + } else if (id === 2) { + //temp_q = temp_q.replace("responseElapsed%3A%5B30000%20TO%20*%5D","connectElapsed%3A%5B30000%20TO%20*%5D"); + temp_q = 'q=' + $scope.panel.value_field + '%3A%5B' + threshold_2_1 + '%20TO%20' + threshold_3 + '%5D' + wt_json + rows_limit + fq + facet + values_mode_query; + } else { + temp_q = 'q=' + $scope.panel.value_field + '%3A%5B' + threshold_3_1 + '%20TO%20' + '*' + '%5D' + wt_json + rows_limit + fq + facet + values_mode_query; } - } else if ($scope.panel.mode === 'values') { - if ($scope.panel.group_field) { - // Group By Field is specified - var groups = results[index].grouped[$scope.panel.group_field].groups; - - for (var j = 0; j < groups.length; j++) { // jshint ignore: line - var docs = groups[j].doclist.docs; - // var numFound = groups[j].doclist.numFound; - var group_time_series = new timeSeries.ZeroFilled({ - interval: _interval, - start_date: _range && _range.from, - end_date: _range && _range.to, - fill_style: 'minimal' - }); - hits = 0; - - // loop through each group results - for (var k = 0; k < docs.length; k++) { - entry_time = new Date(docs[k][time_field]).getTime(); // convert to millisec - entry_value = docs[k][$scope.panel.value_field]; - if($scope.panel.sum_value) { - group_time_series.sumValue(entry_time, entry_value); - }else { - group_time_series.addValue(entry_time, entry_value); - } - - hits += 1; - $scope.hits += 1; - } - $scope.data[j] = { - // info: querySrv.list[id], - // Need to define chart info here according to the results, cannot use querySrv.list[id] - info: { - alias: groups[j].groupValue, - color: querySrv.colors[j], + $scope.panel.queries.query += temp_q + "\n"; + if ($scope.panel.queries.custom !== null) { + request = request.setQuery(temp_q + $scope.panel.queries.custom); + } else { + request = request.setQuery(temp_q); + } + mypromises.push(request.doSearch()); + }); - }, - time_series: group_time_series, - hits: hits - }; - } - } else { // Group By Field is not specified - entries = results[index].response.docs; - for (var j = 0; j < entries.length; j++) { // jshint ignore: line - entry_time = new Date(entries[j][time_field]).getTime(); // convert to millisec - entry_value = entries[j][$scope.panel.value_field]; - time_series.addValue(entry_time, entry_value); - hits += 1; - $scope.hits += 1; - } + } else { - $scope.data[i] = { - info: querySrv.list[id], - time_series: time_series, - hits: hits - }; + _.each($scope.panel.queries.ids, function (id) { + var temp_q = querySrv.getQuery(id) + wt_json + rows_limit + fq + facet + values_mode_query; + + $scope.panel.queries.query += temp_q + "\n"; + if ($scope.panel.queries.custom !== null) { + request = request.setQuery(temp_q + $scope.panel.queries.custom); + } else { + request = request.setQuery(temp_q); } - } + mypromises.push(request.doSearch()); + }); + } - if ($scope.panel.mode !== 'values') { - $scope.data[i] = { - info: querySrv.list[id], - time_series: time_series, - hits: hits - }; - } + if (dashboard.current.services.query.ids.length >= 1) { + $q.all(mypromises).then(function (results) { + $scope.panelMeta.loading = false; + if (segment === 0) { + $scope.hits = 0; + $scope.data = []; + query_id = $scope.query_id = new Date().getTime(); + } + // Convert facet ids to numbers + // var facetIds = _.map(_.keys(results.facets),function(k){return parseInt(k, 10);}); + //var facetIds = [0]; // Need to fix this + + // Make sure we're still on the same query/queries + // TODO: We probably DON'T NEED THIS unless we have to support multiple queries in query module. + // if ($scope.query_id === query_id && _.difference(facetIds, $scope.panel.queries.ids).length === 0) { + var i = 0, + time_series, + hits; + + _.each($scope.panel.queries.ids, function (id, index) { + // Check for error and abort if found + if (!(_.isUndefined(results[index].error))) { + $scope.panel.error = $scope.parse_error(results[index].error.msg); + return; + } + // we need to initialize the data variable on the first run, + // and when we are working on the first segment of the data. + if (_.isUndefined($scope.data[i]) || segment === 0) { + time_series = new timeSeries.ZeroFilled({ + interval: _interval, + start_date: _range && _range.from, + end_date: _range && _range.to, + fill_style: 'minimal' + }); + hits = 0; + } else { + time_series = $scope.data[i].time_series; + // Bug fix for wrong event count: + // Solr don't need to accumulate hits count since it can get total count from facet query. + // Therefore, I need to set hits and $scope.hits to zero. + // hits = $scope.data[i].hits; + hits = 0; + $scope.hits = 0; + } - i++; - }); + // Solr facet counts response is in one big array. + // So no need to get each segment like Elasticsearch does. + var entry_time, entries, entry_value; + if ($scope.panel.mode === 'count' || $scope.panel.mode === 'counts') { + // Entries from facet_ranges counts + entries = results[index].facet_counts.facet_ranges[time_field].counts; + for (var j = 0; j < entries.length; j++) { + entry_time = new Date(entries[j]).getTime(); // convert to millisec + j++; + var entry_count = entries[j]; + var nowTime = new Date().getTime(); + if(entry_time<=nowTime){ + time_series.addValue(entry_time, entry_count); + hits += entry_count; // The series level hits counter + $scope.hits += entry_count; + } + } + } else if ($scope.panel.mode === 'values' || $scope.panel.mode === 'value') { + if ($scope.panel.group_field) { + // Group By Field is specified + var groups = results[index].grouped[$scope.panel.group_field].groups; + + for (var j = 0; j < groups.length; j++) { // jshint ignore: line + var docs = groups[j].doclist.docs; + var group_time_series = new timeSeries.ZeroFilled({ + interval: _interval, + start_date: _range && _range.from, + end_date: _range && _range.to, + fill_style: 'minimal' + }); + hits = 0; + + // loop through each group results + for (var k = 0; k < docs.length; k++) { + entry_time = new Date(docs[k][time_field]).getTime(); // convert to millisec + entry_value = docs[k][$scope.panel.value_field]; + group_time_series.addValue(entry_time, entry_value); + hits += 1; + $scope.hits += 1; + } + + $scope.data[j] = { + // info: querySrv.list[id], + // Need to define chart info here according to the results, cannot use querySrv.list[id] + info: { + alias: groups[j].groupValue, + color: querySrv.colors[j], + + }, + time_series: group_time_series, + hits: hits + }; + } + } else { // Group By Field is not specified + entries = results[index].response.docs; + for (var j = 0; j < entries.length; j++) { // jshint ignore: line + entry_time = new Date(entries[j][time_field]).getTime(); // convert to millisec + entry_value = entries[j][$scope.panel.value_field]; + time_series.addValue(entry_time, entry_value); + hits += 1; + $scope.hits += 1; + } + + $scope.data[i] = { + info: querySrv.list[id], + time_series: time_series, + hits: hits + }; + } + } - // Tell the histogram directive to render. - $scope.$emit('render'); - // } - }); - } + if ($scope.panel.mode !== 'values' || $scope.panel.mode !== 'value') { + $scope.data[i] = { + info: querySrv.list[id], + time_series: time_series, + hits: hits + }; + } + + i++; + }); + + // Tell the histogram directive to render. + $scope.$emit('render'); + // } + }); + } + } }; // function $scope.zoom @@ -483,7 +521,6 @@ function (angular, app, $, _, kbn, moment, timeSeries) { }); dashboard.refresh(); - }; // I really don't like this function, too much dom manip. Break out into directive? @@ -496,23 +533,20 @@ function (angular, app, $, _, kbn, moment, timeSeries) { }; $scope.close_edit = function() { - // Start refresh timer if enabled - if ($scope.panel.refresh.enable) { - $scope.set_timer($scope.panel.refresh.interval); - } - if ($scope.refresh) { + if($scope.refresh) { $scope.get_data(); } - $scope.refresh = false; + $scope.refresh = false; $scope.$emit('render'); }; $scope.render = function() { $scope.$emit('render'); }; + }); - module.directive('histogramChart', function(dashboard, filterSrv) { + module.directive('histogramChart', function(dashboard, filterSrv) { return { restrict: 'A', template: '
', @@ -532,12 +566,29 @@ function (angular, app, $, _, kbn, moment, timeSeries) { function render_panel() { // IE doesn't work without this elem.css({height:scope.panel.height || scope.row.height}); - + // Populate from the query service + var num_all = 0; + + _.each(scope.data, function(seri) { + num_all += seri.hits; + }); try { + var label_i = 0; _.each(scope.data, function(series) { + series.color = series.info.color; + label_i ++; + //series.color = '%'; + var mid = parseFloat((100*series.hits/num_all).toFixed(2)); + series.hits = mid; + if(label_i === 2){ + series.info.alias = "Warning% "; + }else if(label_i === 3){ + series.info.alias = "Normal% "; + }else if(label_i === 1){ + series.info.alias = "Risk% ";} series.label = series.info.alias; - series.color = series.info.color; + }); } catch(e) {return;} @@ -545,7 +596,29 @@ function (angular, app, $, _, kbn, moment, timeSeries) { var barwidth = kbn.interval_to_ms(scope.panel.interval); var stack = scope.panel.stack ? true : null; - + + var xLabel = ""; + var xunit =' '; + + if(scope.panel.value_field === 'cpu'){ + xunit ='%'; + }else if(scope.panel.value_field === 'UsedMemery'){ + xunit ='MB'; + }else if(scope.panel.value_field === 'FreeDiskSpace'){ + xunit ='GB'; + } + if(scope.panel.mode === 'value'||scope.panel.mode === 'counts'){ + if (scope.panel.segment === 5){ + xLabel = "Threshold:"+' '+scope.panel.threshold_first+' and '+scope.panel.threshold_second+' and '+scope.panel.threshold_third; + }else if(scope.panel.segment === 3 ||scope.panel.segment === 4){ + xLabel = "Warning:>="+' '+scope.panel.threshold_first+xunit+' and <'+scope.panel.threshold_second+xunit+';'+'Risk:>='+scope.panel.threshold_second+xunit; + if(scope.panel.reverse){ + xLabel = "Warning:>"+' '+scope.panel.threshold_first+xunit+' and <='+scope.panel.threshold_second+xunit+';'+'Risk:<='+scope.panel.threshold_first+xunit; + } + }else if(scope.panel.segment === 2){ + xLabel = "Threshold:"+scope.panel.threshold_first; + } + } // Populate element try { var options = { @@ -580,19 +653,22 @@ function (angular, app, $, _, kbn, moment, timeSeries) { }, yaxis: { show: scope.panel['y-axis'], - min: null, // TODO - make this adjusted dynamicmally, and add it to configuration panel - max: scope.panel.percentage && scope.panel.stack ? 100 : null, + min:0, + + //min: null, // TODO - make this adjusted dynamicmally, and add it to configuration panel + //max: scope.panel.percentage && scope.panel.stack ? 100 : null, axisLabel: scope.panel.mode, }, xaxis: { timezone: scope.panel.timezone, - show: scope.panel['x-axis'], + show: 1, mode: "time", - min: _.isUndefined(scope.range.from) ? null : scope.range.from.getTime(), - max: _.isUndefined(scope.range.to) ? null : scope.range.to.getTime(), + + //min: _.isUndefined(scope.range.from) ? null : scope.range.from.getTime(), + //max: _.isUndefined(scope.range.to) ? null : scope.range.to.getTime(), timeformat: time_format(scope.panel.interval), label: "Datetime", - axisLabel: filterSrv.getTimeField(), + axisLabel: scope.panel['x-axis']?xLabel:'', }, grid: { backgroundColor: null, @@ -642,7 +718,7 @@ function (angular, app, $, _, kbn, moment, timeSeries) { scope.plot = $.plot(elem, scope.data, options); } catch(e) { // TODO: Need to fix bug => "Invalid dimensions for plot, width = 0, height = 200" - console.log(e); + // console.log(e); } } @@ -662,13 +738,45 @@ function (angular, app, $, _, kbn, moment, timeSeries) { } var $tooltip = $('
'); + /* elem.bind("plothover", function (event, pos, item) { var group, value; + var allSeries = scope.plot.getData(); if (item) { - if (item.series.info.alias || scope.panel.tooltip.query_as_alias) { + + if (item.series.info.alias.substring(0,item.series.info.alias.length-2) || scope.panel.tooltip.query_as_alias) { group = '' + '' + ' ' + - (item.series.info.alias || item.series.info.query)+ + (item.series.info.alias.substring(0,item.series.info.alias.length-2) || item.series.info.query)+ + '
'; + } else { + group = kbn.query_color_dot(item.series.color, 15) + ' '; + } + if (scope.panel.stack && scope.panel.tooltip.value_type === 'individual') { + value = item.datapoint[1] - item.datapoint[2]; + } else { + value = item.datapoint[1]; + } + $tooltip + .html( + group + dashboard.numberWithCommas(value) + " @ " + (scope.panel.timezone === 'utc'? moment.utc(item.datapoint[0]).format('MM/DD HH:mm:ss') : moment(item.datapoint[0]).format('MM/DD HH:mm:ss')) + // group + dashboard.numberWithCommas(value) + " @ " + moment(item.datapoint[0]).format('MM/DD HH:mm:ss') + // group + dashboard.numberWithCommas(value) + " @ " + moment(item.datapoint[0]) + ) + .place_tt(pos.pageX, pos.pageY); + } else { + $tooltip.detach(); + } + }); + */ + + elem.bind("plothover", function (event, pos, item) { + var group, value; + if (item) { + if (item.series.info.alias.substring(0,item.series.info.alias.length-2) || scope.panel.tooltip.query_as_alias) { + group = '' + + '' + ' ' + + (item.series.info.alias.substring(0,item.series.info.alias.length-2) || item.series.info.query)+ '
'; } else { group = kbn.query_color_dot(item.series.color, 15) + ' '; @@ -680,16 +788,28 @@ function (angular, app, $, _, kbn, moment, timeSeries) { } var lnLastValue = value; - + var isr =0; + var isnormal = 3; + var lbPositiveValue = (lnLastValue>0); - - var lsItemTT = group + dashboard.numberWithCommas(value) + " @ " + (scope.panel.timezone === 'utc'? moment.utc(item.datapoint[0]).format('MM/DD HH:mm:ss') : moment(item.datapoint[0]).format('MM/DD HH:mm:ss')); - + + var lsItemTT=""; + var lsTT=""; + var isgroup = group; + var isvalue = value; + if(scope.panel.mode !== 'value' || lnLastValue !==0){ + lsItemTT = group + dashboard.numberWithCommas(value) + " @ " + (scope.panel.timezone === 'utc'? moment.utc(item.datapoint[0]).format('MM/DD HH:mm:ss') : moment(item.datapoint[0]).format('MM/DD HH:mm:ss')); + lsTT = lsItemTT; + isr =1; + }else{ + isnormal--; + } + var hoverSeries = item.series; var x = item.datapoint[0]; // y = item.datapoint[1]; - var lsTT = lsItemTT; + var allSeries = scope.plot.getData(); var posSerie = -1; for (var i= allSeries.length - 1 ; i>=0; i--) { @@ -733,41 +853,57 @@ function (angular, app, $, _, kbn, moment, timeSeries) { lnLastValue = value; - if (s.info.alias || scope.panel.tooltip.query_as_alias) { + if (s.info.alias.substring(0,s.info.alias.length-2) || scope.panel.tooltip.query_as_alias) { group = '' + '' + ' ' + - (s.info.alias || s.info.query)+ + (s.info.alias.substring(0,s.info.alias.length-2) || s.info.query)+ '
'; } else { group = kbn.query_color_dot(s.color, 15) + ' '; } - + + if(scope.panel.mode !== 'value' || lnLastValue !==0){ + lsItemTT = group + dashboard.numberWithCommas(value) + " @ " + (scope.panel.timezone === 'utc'? moment.utc(p[0]).format('MM/DD HH:mm:ss') : moment(p[0]).format('MM/DD HH:mm:ss')); lsTT = lsTT +"
"+ lsItemTT; + isr=1; + }else{ + isnormal--; + } break; } } } - + + if(!isnormal){ + lsItemTT = isgroup + dashboard.numberWithCommas(isvalue) + " @ " + (scope.panel.timezone === 'utc'? moment.utc(item.datapoint[0]).format('MM/DD HH:mm:ss') : moment(item.datapoint[0]).format('MM/DD HH:mm:ss')); + lsTT = lsItemTT; + isr=1; + } + if(isr){ $tooltip .html( lsTT ) .place_tt(pos.pageX, pos.pageY); + } } else { $tooltip.detach(); } }); - elem.bind("plotselected", function (event, ranges) { - filterSrv.set({ - type : 'time', - // from : moment.utc(ranges.xaxis.from), - // to : moment.utc(ranges.xaxis.to), - from : moment.utc(ranges.xaxis.from).toDate(), - to : moment.utc(ranges.xaxis.to).toDate(), - field : filterSrv.getTimeField() - }); - dashboard.refresh(); + + filterSrv.set({ + type: 'time', + // from : moment.utc(ranges.xaxis.from), + // to : moment.utc(ranges.xaxis.to), + from: moment.utc(ranges.xaxis.from).toDate(), + to: moment.utc(ranges.xaxis.to).toDate(), + field: filterSrv.getTimeField() + }); + dashboard.current.linkage_id = scope.panel.linkage_id; + dashboard.current.enable_linkage =false; + dashboard.refresh(); + }); } }; diff --git a/src/app/panels/histogram/timeSeries.js b/src/app/panels/histogram/timeSeries.js old mode 100755 new mode 100644 index c12587e85..96054fa7d --- a/src/app/panels/histogram/timeSeries.js +++ b/src/app/panels/histogram/timeSeries.js @@ -68,30 +68,6 @@ function (_, Interval) { this._cached_times = null; }; - /** - * Add a row and sum the value - * @param {int} time The time for the value, in - * @param {any} value The value at this time - */ - ts.ZeroFilled.prototype.sumValue = function (time, value) { - if (time instanceof Date) { - time = getDatesTime(time); - } else { - time = base10Int(time); - } - if (!isNaN(time)) { - - var curValue = 0; - if (!isNaN(this._data[time])){ - curValue = this._data[time]; - } - - - this._data[time] = curValue + (_.isUndefined(value) ? 0 : value); - } - this._cached_times = null; - }; - /** * Get an array of the times that have been explicitly set in the series * @param {array} include (optional) list of timestamps to include in the response @@ -200,4 +176,4 @@ function (_, Interval) { return ts; -}); +}); \ No newline at end of file diff --git a/src/app/panels/histogramt/editor.html b/src/app/panels/histogramt/editor.html new file mode 100644 index 000000000..9a785908b --- /dev/null +++ b/src/app/panels/histogramt/editor.html @@ -0,0 +1,146 @@ +
+
+ + + + +
+
+ + +
+
+ + +
+
+ + +
+
+ In {{panel.mode}} mode the configured field must be a numeric type. +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+ + +
+
+ +
+
+ + +
+ +
+ +
Chart Settings
+
+
+
+
+
+
+ + +
+
+
+
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ + +
+
+ +
Tooltip Settings
+
+
+ + +
+
+ + +
+
+
+
Linkage Effective
+
+ +
+ +
diff --git a/src/app/panels/histogramt/interval.js b/src/app/panels/histogramt/interval.js new file mode 100644 index 000000000..673371fcf --- /dev/null +++ b/src/app/panels/histogramt/interval.js @@ -0,0 +1,57 @@ +define([ + 'kbn' +], +function (kbn) { + 'use strict'; + + /** + * manages the interval logic + * @param {[type]} interval_string An interval string in the format '1m', '1y', etc + */ + function Interval(interval_string) { + this.string = interval_string; + + var info = kbn.describe_interval(interval_string); + this.type = info.type; + this.ms = info.sec * 1000 * info.count; + + // does the length of the interval change based on the current time? + if (this.type === 'y' || this.type === 'M') { + // we will just modify this time object rather that create a new one constantly + this.get = this.get_complex; + this.date = new Date(0); + } else { + this.get = this.get_simple; + } + } + + Interval.prototype = { + toString: function () { + return this.string; + }, + after: function(current_ms) { + return this.get(current_ms, 1); + }, + before: function (current_ms) { + return this.get(current_ms, -1); + }, + get_complex: function (current, delta) { + this.date.setTime(current); + switch(this.type) { + case 'M': + this.date.setUTCMonth(this.date.getUTCMonth() + delta); + break; + case 'y': + this.date.setUTCFullYear(this.date.getUTCFullYear() + delta); + break; + } + return this.date.getTime(); + }, + get_simple: function (current, delta) { + return current + (delta * this.ms); + } + }; + + return Interval; + +}); \ No newline at end of file diff --git a/src/app/panels/histogramt/module.html b/src/app/panels/histogramt/module.html new file mode 100644 index 000000000..70bcf9183 --- /dev/null +++ b/src/app/panels/histogramt/module.html @@ -0,0 +1,96 @@ +
+ +
+
+ + + View + |  + + + + Zoom Out |  + + + + {{series.info.alias.substring(0,series.info.alias.length-2)}} ({{series.hits}}{{series.info.alias.substr(-2)}}) + + +
+
+ + + + + + + + + + + + + +
+ +
+
+ + + +
+
+
+
+
diff --git a/src/app/panels/histogramt/module.js b/src/app/panels/histogramt/module.js new file mode 100644 index 000000000..064d49011 --- /dev/null +++ b/src/app/panels/histogramt/module.js @@ -0,0 +1,937 @@ +/* + + ## Histogram + + ### Parameters + * auto_int :: Auto calculate data point interval? + * resolution :: If auto_int is enables, shoot for this many data points, rounding to + sane intervals + * interval :: Datapoint interval in elasticsearch date math format (eg 1d, 1w, 1y, 5y) + * fill :: Only applies to line charts. Level of area shading from 0-10 + * linewidth :: Only applies to line charts. How thick the line should be in pixels + While the editor only exposes 0-10, this can be any numeric value. + Set to 0 and you'll get something like a scatter plot + * timezone :: This isn't totally functional yet. Currently only supports browser and utc. + browser will adjust the x-axis labels to match the timezone of the user's + browser + * spyable :: Dislay the 'eye' icon that show the last elasticsearch query + * zoomlinks :: Show the zoom links? + * bars :: Show bars in the chart + * stack :: Stack multiple queries. This generally a crappy way to represent things. + You probably should just use a line chart without stacking + * points :: Should circles at the data points on the chart + * lines :: Line chart? Sweet. + * legend :: Show the legend? + * x-axis :: Show x-axis labels and grid lines + * y-axis :: Show y-axis labels and grid lines + * interactive :: Allow drag to select time range + +*/ +define([ + 'angular', + 'app', + 'jquery', + 'underscore', + 'kbn', + 'moment', + './timeSeries', + + 'jquery.flot', + 'jquery.flot.pie', + 'jquery.flot.selection', + 'jquery.flot.time', + 'jquery.flot.stack', + 'jquery.flot.stackpercent', + 'jquery.flot.axislabels' +], +function (angular, app, $, _, kbn, moment, timeSeries) { + 'use strict'; + var bmw_total; + var bmw_total_disk; + var bmw_total_memory; + var module = angular.module('kibana.panels.histogramt', []); + app.useModule(module); + + module.controller('histogramt', function($scope, $q, querySrv, dashboard, filterSrv) { + $scope.panelMeta = { + + editorTabs : [ + { + title:'Queries', + src:'app/partials/querySelect.html' + } + ], + status : "Stable", + description : "A bucketed time series chart of the current query, including all applied time and non-time filters, when used in count mode. Uses Solr’s facet.range query parameters. In values mode, it plots the value of a specific field over time, and allows the user to group field values by a second field." + }; + + // Set and populate defaults + var _d = { + mode : 'value', + queries : { + mode : 'all', + ids : [], + query : '*:*', + custom : '' + }, + max_rows : 100000, // maximum number of rows returned from Solr (also use this for group.limit to simplify UI setting) + reverse :0, + segment :4, + threshold_first:1000, + threshold_second:2000, + threshold_third:3000, + value_field : null, + group_field : null, + auto_int : true, + linkage_id:'a', + total_first :'%', + field_color:'#209bf8', + resolution : 100, + interval : '5m', + intervals : ['auto','1s','1m','5m','10m','30m','1h','3h','12h','1d','1w','1M','1y'], + fill : 0, + linewidth : 3, + display:'block', + icon:"icon-caret-down", + timezone : 'browser', // browser, utc or a standard timezone + spyable : true, + zoomlinks : true, + bars : true, + stack : true, + points : false, + lines : false, + lines_smooth: false, // Enable 'smooth line' mode by removing zero values from the plot. + legend : true, + 'x-axis' : true, + 'y-axis' : true, + percentage : false, + interactive : true, + options : true, + show_queries:true, + tooltip : { + value_type: 'cumulative', + query_as_alias: false + } + }; + + _.defaults($scope.panel,_d); + + $scope.init = function() { + // Hide view options by default + $scope.options = false; + $scope.$on('refresh',function(){ + $scope.get_data(); + }); + + $scope.get_data(); + + }; + + $scope.set_interval = function(interval) { + if(interval !== 'auto') { + $scope.panel.auto_int = false; + $scope.panel.interval = interval; + } else { + $scope.panel.auto_int = true; + } + }; + + $scope.display=function() { + if($scope.panel.display=='none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; + + $scope.interval_label = function(interval) { + return $scope.panel.auto_int && interval === $scope.panel.interval ? interval+" (auto)" : interval; + }; + + /** + * The time range effecting the panel + * @return {[type]} [description] + */ + $scope.get_time_range = function () { + var range = $scope.range = filterSrv.timeRange('min'); + return range; + }; + + $scope.get_interval = function () { + var interval = $scope.panel.interval, + range; + if ($scope.panel.auto_int) { + range = $scope.get_time_range(); + if (range) { + interval = kbn.secondsToHms( + kbn.calculate_interval(range.from, range.to, $scope.panel.resolution, 0) / 1000 + ); + } + } + $scope.panel.interval = interval || '10m'; + return $scope.panel.interval; + }; + + /** + * Fetch the data for a chunk of a queries results. Multiple segments occur when several indicies + * need to be consulted (like timestamped logstash indicies) + * + * The results of this function are stored on the scope's data property. This property will be an + * array of objects with the properties info, time_series, and hits. These objects are used in the + * render_panel function to create the historgram. + * + * !!! Solr does not need to fetch the data in chunk because it uses a facet search and retrieve + * !!! all events from a single query. + * + * @param {number} segment The segment count, (0 based) + * @param {number} query_id The id of the query, generated on the first run and passed back when + * this call is made recursively for more segments + */ + $scope.get_data = function(segment, query_id) { + if(($scope.panel.linkage_id==dashboard.current.linkage_id)||dashboard.current.enable_linkage){ + if (_.isUndefined(segment)) { + segment = 0; + } + delete $scope.panel.error; + + // Make sure we have everything for the request to complete + if (dashboard.indices.length === 0) { + return; + } + var _range = $scope.get_time_range(); + var _interval = $scope.get_interval(_range); + + if ($scope.panel.auto_int) { + $scope.panel.interval = kbn.secondsToHms( + kbn.calculate_interval(_range.from, _range.to, $scope.panel.resolution, 0) / 1000); + } + + $scope.panelMeta.loading = true; + + // Solr + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + var request = $scope.sjs.Request().indices(dashboard.indices[segment]); + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + + + $scope.panel.queries.query = ""; + // Build the query + _.each($scope.panel.queries.ids, function (id) { + var query = $scope.sjs.FilteredQuery( + querySrv.getEjsObj(id), + filterSrv.getBoolFilter(filterSrv.ids) + ); + + var facet = $scope.sjs.DateHistogramFacet(id); + if ($scope.panel.mode === 'count' || $scope.panel.mode === 'counts') { + facet = facet.field(filterSrv.getTimeField()); + } else { + if (_.isNull($scope.panel.value_field)) { + $scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified"; + return; + } + facet = facet.keyField(filterSrv.getTimeField()).valueField($scope.panel.value_field); + } + facet = facet.interval(_interval).facetFilter($scope.sjs.QueryFilter(query)); + request = request.facet(facet).size(0); + + }); + + // Populate the inspector panel + $scope.populate_modal(request); + + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + } + var time_field = filterSrv.getTimeField(); + var start_time = filterSrv.getStartTime(); + var end_time = filterSrv.getEndTime(); + + // facet.range.end does NOT accept * as a value, need to convert it to NOW + if (end_time === '*') { + end_time = 'NOW'; + } + + var wt_json = '&wt=json'; + var rows_limit = '&rows=0'; // for histogram, we do not need the actual response doc, so set rows=0 + var facet_gap = $scope.sjs.convertFacetGap($scope.panel.interval); + var facet = '&facet=true' + + '&facet.range=' + time_field + + '&facet.range.start=' + start_time + + '&facet.range.end=' + end_time + + '&facet.range.gap=' + facet_gap; + var values_mode_query = ''; + + // For mode = value + if ($scope.panel.mode === 'values' || $scope.panel.mode === 'value') { + if (!$scope.panel.value_field) { + $scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified"; + return; + } + + values_mode_query = '&fl=' + time_field + ' ' + $scope.panel.value_field; + + rows_limit = '&rows=' + $scope.panel.max_rows; + facet = ''; + + // if Group By Field is specified + if ($scope.panel.group_field) { + values_mode_query += '&group=true&group.field=' + $scope.panel.group_field + '&group.limit=' + $scope.panel.max_rows; + } + } + + var mypromises = []; + var threshold_1 = '*'; + var threshold_2 = '*'; + var threshold_3 = '*'; + var staticfield = $scope.panel.value_field; + if ($scope.panel.mode === 'value' || $scope.panel.mode === 'counts') { + var arr_id = [0]; + if ($scope.panel.segment === 2) { + arr_id = [1, 0]; + threshold_1 = String($scope.panel.threshold_first); + } else if ($scope.panel.segment === 3) { + arr_id = [2, 1, 0]; + threshold_1 = String($scope.panel.threshold_first); + threshold_2 = String($scope.panel.threshold_second); + } else if ($scope.panel.segment === 4) { + arr_id = [4, 3, 2, 1, 0]; + if ($scope.panel.reverse === 0) { + arr_id = [2, 1, 0, 3, 4]; + } else { + arr_id = [4, 3, 2, 1, 0]; + } + threshold_1 = String($scope.panel.threshold_first); + threshold_2 = String($scope.panel.threshold_second); + // = String($scope.panel.threshold_third); + } + if ($scope.panel.reverse === 1) { + arr_id = arr_id.reverse(); + } + _.each(arr_id, function (id) { + if (id === 0) { + var threshold_a = threshold_1 - 1; + //temp_q = temp_q.replace(/responseElapsed%3A%5B0%20TO%2020000%5D/,"connectElapsed%3A%5B0%20TO%2020000%5D"); + var temp_q = 'q=' + $scope.panel.value_field + '%3A%5B' + 0 + '%20TO%20' + threshold_a + '%5D' + wt_json + rows_limit + fq + facet + values_mode_query; + } + else if (id === 1) { + var threshold_b = threshold_2 - 1; + //temp_q = temp_q.replace(/responseElapsed%3A%5B20000%20TO%2030000%5D/,"connectElapsed%3A%5B20000%20TO%2030000%5D"); + var temp_q = 'q=' + $scope.panel.value_field + '%3A%5B' + threshold_1 + '%20TO%20' + threshold_b + '%5D' + wt_json + rows_limit + fq + facet + values_mode_query; + } else if (id === 2) { + //temp_q = temp_q.replace("responseElapsed%3A%5B30000%20TO%20*%5D","connectElapsed%3A%5B30000%20TO%20*%5D"); + var temp_q = 'q=' + $scope.panel.value_field + '%3A%5B' + threshold_2 + '%20TO%20' + threshold_3 + '%5D' + wt_json + rows_limit + fq + facet + values_mode_query; + } else if (id === 3) { + //var temp_q = 'q='+$scope.panel.value_field + '%3A%5B' +threshold_3+'%20TO%20'+'*'+'%5D'+wt_json + rows_limit + fq + facet + values_mode_query; + var temp_q = 'q=' + $scope.panel.value_field1 + '%3A%5B' + '*' + '%20TO%20' + '*' + '%5D' + wt_json + rows_limit + fq + facet + '&fl=' + time_field + ' ' + $scope.panel.value_field1; + + } else { + var temp_q = 'q=' + $scope.panel.value_field2 + '%3A%5B' + '*' + '%20TO%20' + '*' + '%5D' + wt_json + rows_limit + fq + facet + '&fl=' + time_field + ' ' + $scope.panel.value_field2; + + } + + + $scope.panel.queries.query += temp_q + "\n"; + if ($scope.panel.queries.custom !== null) { + request = request.setQuery(temp_q + $scope.panel.queries.custom); + } else { + request = request.setQuery(temp_q); + } + mypromises.push(request.doSearch()); + }); + + + } else { + + _.each($scope.panel.queries.ids, function (id) { + var temp_q = querySrv.getQuery(id) + wt_json + rows_limit + fq + facet + values_mode_query; + + $scope.panel.queries.query += temp_q + "\n"; + if ($scope.panel.queries.custom !== null) { + request = request.setQuery(temp_q + $scope.panel.queries.custom); + } else { + request = request.setQuery(temp_q); + } + mypromises.push(request.doSearch()); + }); + } + + if (dashboard.current.services.query.ids.length >= 1) { + $q.all(mypromises).then(function (results) { + $scope.panelMeta.loading = false; + if (segment === 0) { + $scope.hits = 0; + $scope.data = []; + query_id = $scope.query_id = new Date().getTime(); + } + // Convert facet ids to numbers + // var facetIds = _.map(_.keys(results.facets),function(k){return parseInt(k, 10);}); + //var facetIds = [0]; // Need to fix this + + // Make sure we're still on the same query/queries + // TODO: We probably DON'T NEED THIS unless we have to support multiple queries in query module. + // if ($scope.query_id === query_id && _.difference(facetIds, $scope.panel.queries.ids).length === 0) { + var i = 0, + time_series, + hits; + + _.each($scope.panel.queries.ids, function (id, index) { + // Check for error and abort if found + if (!(_.isUndefined(results[index].error))) { + $scope.panel.error = $scope.parse_error(results[index].error.msg); + return; + } + // we need to initialize the data variable on the first run, + // and when we are working on the first segment of the data. + if (_.isUndefined($scope.data[i]) || segment === 0) { + time_series = new timeSeries.ZeroFilled({ + interval: _interval, + start_date: _range && _range.from, + end_date: _range && _range.to, + fill_style: 'minimal' + }); + hits = 0; + } else { + time_series = $scope.data[i].time_series; + // Bug fix for wrong event count: + // Solr don't need to accumulate hits count since it can get total count from facet query. + // Therefore, I need to set hits and $scope.hits to zero. + // hits = $scope.data[i].hits; + hits = 0; + $scope.hits = 0; + } + + // Solr facet counts response is in one big array. + // So no need to get each segment like Elasticsearch does. + var entry_time, entries, entry_value; + if ($scope.panel.mode === 'count' || $scope.panel.mode === 'counts') { + // Entries from facet_ranges counts + entries = results[index].facet_counts.facet_ranges[time_field].counts; + for (var j = 0; j < entries.length; j++) { + entry_time = new Date(entries[j]).getTime(); // convert to millisec + j++; + var entry_count = entries[j]; + var nowTime = new Date().getTime(); + if(entry_time<=nowTime){ + time_series.addValue(entry_time, entry_count); + hits += entry_count; // The series level hits counter + $scope.hits += entry_count; + } + } + } else if ($scope.panel.mode === 'values' || $scope.panel.mode === 'value') { + if ($scope.panel.group_field) { + // Group By Field is specified + var groups = results[index].grouped[$scope.panel.group_field].groups; + + for (var j = 0; j < groups.length; j++) { // jshint ignore: line + var docs = groups[j].doclist.docs; + var group_time_series = new timeSeries.ZeroFilled({ + interval: _interval, + start_date: _range && _range.from, + end_date: _range && _range.to, + fill_style: 'minimal' + }); + hits = 0; + + // loop through each group results + for (var k = 0; k < docs.length; k++) { + entry_time = new Date(docs[k][time_field]).getTime(); // convert to millisec + entry_value = docs[k][$scope.panel.value_field]; + + group_time_series.addValue(entry_time, entry_value); + hits += 1; + $scope.hits += 1; + } + + $scope.data[j] = { + // info: querySrv.list[id], + // Need to define chart info here according to the results, cannot use querySrv.list[id] + info: { + alias: groups[j].groupValue, + color: querySrv.colors[j], + + }, + time_series: group_time_series, + hits: hits + }; + } + } else { // Group By Field is not specified + entries = results[index].response.docs; + for (var j = 0; j < entries.length; j++) { // jshint ignore: line + entry_time = new Date(entries[j][time_field]).getTime(); // convert to millisec + + entry_value = entries[j][$scope.panel.value_field]; + + time_series.addValue(entry_time, entry_value); + hits += 1; + $scope.hits += 1; + } + + $scope.data[i] = { + info: querySrv.list[id], + time_series: time_series, + hits: hits + }; + } + } + if ($scope.panel.segment == 4) { + var entry_time1, entries1, entry_value1, entries2; + var hits1 = 0; + var arry = new Array(); + var object = new Object(); + object.alias = $scope.panel.value_field1; + object.color = $scope.panel.field_color; + arry.push(object); + entries1 = results[3].response.docs; + entries2 = results[4].response.docs; + //bmw_total = entries2[entries2.length - 1][$scope.panel.value_field2][0]; + bmw_total = entries2[entries2.length - 1][$scope.panel.value_field2]; + if ($scope.panel.value_field === 'UsedMemery'||$scope.panel.value_field === 'UsedMemory') { + bmw_total_memory = bmw_total; + } else if ($scope.panel.value_field === 'FreeDiskSpace'||$scope.panel.value_field === 'UsedDisk') { + bmw_total_disk = bmw_total; + } + var time_series1 = new timeSeries.ZeroFilled({ + interval: _interval, + start_date: _range && _range.from, + end_date: _range && _range.to, + fill_style: 'minimal' + }); + for (var j = 0; j < entries1.length; j++) { // jshint ignore: line + entry_time1 = new Date(entries1[j][time_field]).getTime(); // convert to millisec + entry_value1 = entries1[j][$scope.panel.value_field1]; + time_series1.addValue(entry_time1, entry_value1); + hits1 += 1; + + } + + $scope.data[3] = { + info: arry[0], + time_series: time_series1, + hits: hits1 + }; + } + + if ($scope.panel.mode !== 'values' || $scope.panel.mode !== 'value') { + $scope.data[i] = { + info: querySrv.list[id], + time_series: time_series, + hits: hits + }; + } + + i++; + }); + + // Tell the histogram directive to render. + $scope.$emit('render'); + // } + }); + } + } + }; + + // function $scope.zoom + // factor :: Zoom factor, so 0.5 = cuts timespan in half, 2 doubles timespan + $scope.zoom = function(factor) { + var _range = filterSrv.timeRange('min'); + var _timespan = (_range.to.valueOf() - _range.from.valueOf()); + var _center = _range.to.valueOf() - _timespan/2; + + var _to = (_center + (_timespan*factor)/2); + var _from = (_center - (_timespan*factor)/2); + + // If we're not already looking into the future, don't. + if(_to > Date.now() && _range.to < Date.now()) { + var _offset = _to - Date.now(); + _from = _from - _offset; + _to = Date.now(); + } + + var time_field = filterSrv.getTimeField(); + if(factor > 1) { + filterSrv.removeByType('time'); + } + + filterSrv.set({ + type:'time', + from:moment.utc(_from).toDate(), + to:moment.utc(_to).toDate(), + field:time_field + }); + + dashboard.refresh(); + }; + + // I really don't like this function, too much dom manip. Break out into directive? + $scope.populate_modal = function(request) { + $scope.inspector = angular.toJson(JSON.parse(request.toString()),true); + }; + + $scope.set_refresh = function (state) { + $scope.refresh = state; + }; + + $scope.close_edit = function() { + if($scope.refresh) { + $scope.get_data(); + } + $scope.refresh = false; + $scope.$emit('render'); + }; + + $scope.render = function() { + $scope.$emit('render'); + }; + + }); + + module.directive('histogramtChart', function(dashboard, filterSrv) { + return { + restrict: 'A', + template: '
', + link: function(scope, elem) { + + // Receive render events + scope.$on('render',function(){ + render_panel(); + }); + + // Re-render if the window is resized + angular.element(window).bind('resize', function(){ + render_panel(); + }); + + // Function for rendering panel + function render_panel() { + // IE doesn't work without this + elem.css({height:scope.panel.height || scope.row.height}); + + // Populate from the query service + var num_all = 0; + + _.each(scope.data, function(seri) { + if (seri.info.alias != scope.panel.value_field1 && seri.info.alias != "TotalMB" && seri.info.alias != "TotalGB"){ + num_all += seri.hits;} + }); + try { + var label_i = 0; + _.each(scope.data, function(series) { + series.color = series.info.color; + label_i++; + if (series.info.alias == scope.panel.value_field1 || series.info.alias =="TotalMB" || series.info.alias =="TotalGB"){ + if(scope.panel.value_field === 'UsedMemery'||scope.panel.value_field === 'UsedMemory'){ + series.info.alias = "TotalMB"; + series.hits =bmw_total_memory; + }else if(scope.panel.value_field === 'FreeDiskSpace'||scope.panel.value_field === 'UsedDisk'){ + series.info.alias = "TotalMB"; + series.hits =bmw_total_disk; + }else{ + series.info.alias = "Total "; + series.hits =bmw_total; + } + //series.color = ''; + //series.hits =bmw_total; + }else{ + //series.color = '%'; + var mid = parseFloat((100*series.hits/num_all).toFixed(2)); + series.hits = mid; + if(label_i == 2){ + series.info.alias = "Warning% "; + }else if(label_i == 3){ + series.info.alias = "Normal% "; + }else if(label_i == 1){ + series.info.alias = "Risk% ";} + series.label = series.info.alias; + } + }); + } catch(e) {return;} + + // Set barwidth based on specified interval + var barwidth = kbn.interval_to_ms(scope.panel.interval); + + var stack = scope.panel.stack ? true : null; + + var xLabel = ""; + var xunit ='MB'; + + if(scope.panel.value_field === 'cpu'){ + xunit ='%'; + }else if(scope.panel.value_field === 'UsedMemery'){ + xunit ='MB'; + }else if(scope.panel.value_field === 'FreeDiskSpace'){ + xunit ='GB'; + } + if(scope.panel.mode === 'value'){ + if (scope.panel.segment === 5){ + xLabel = "Threshold:"+' '+scope.panel.threshold_first+' and '+scope.panel.threshold_second+' and '+scope.panel.threshold_third; + }else if(scope.panel.segment === 3 ||scope.panel.segment === 4){ + xLabel = "Warning:>="+' '+scope.panel.threshold_first+xunit+' and <'+scope.panel.threshold_second+xunit+';'+'Risk:>='+scope.panel.threshold_second+xunit; + if(scope.panel.reverse){ + xLabel = "Warning:>="+' '+scope.panel.threshold_first+xunit+' and <'+scope.panel.threshold_second+xunit+';'+'Risk:<'+scope.panel.threshold_first+xunit; + } + }else if(scope.panel.segment === 2){ + xLabel = "Threshold:"+scope.panel.threshold_first; + } + } + // Populate element + try { + var options = { + legend: { show: false }, + series: { + stackpercent: scope.panel.stack ? scope.panel.percentage : false, + stack: scope.panel.percentage ? null : stack, + lines: { + show: scope.panel.lines, + // Silly, but fixes bug in stacked percentages + fill: scope.panel.fill === 0 ? 0.001 : scope.panel.fill/10, + lineWidth: scope.panel.linewidth, + steps: false + }, + bars: { + show: scope.panel.bars, + fill: 1, + barWidth: barwidth/1.8, + zero: false, + lineWidth: 0 + }, + points: { + show: scope.panel.points, + fill: 1, + fillColor: false, + radius: 5 + }, + shadowSize: 1 + }, + axisLabels: { + show: true + }, + yaxis: { + show: scope.panel['y-axis'], + min:0, + + //min: null, // TODO - make this adjusted dynamicmally, and add it to configuration panel + //max: scope.panel.percentage && scope.panel.stack ? 100 : null, + axisLabel: scope.panel.mode, + }, + xaxis: { + timezone: scope.panel.timezone, + show: scope.panel['x-axis'], + mode: "time", + + //min: _.isUndefined(scope.range.from) ? null : scope.range.from.getTime(), + //max: _.isUndefined(scope.range.to) ? null : scope.range.to.getTime(), + timeformat: time_format(scope.panel.interval), + label: "Datetime", + axisLabel: xLabel, + }, + grid: { + backgroundColor: null, + borderWidth: 0, + hoverable: true, + color: '#c8c8c8' + } + }; + + if(scope.panel.interactive) { + options.selection = { mode: "x", color: '#666' }; + } + + // when rendering stacked bars, we need to ensure each point that has data is zero-filled + // so that the stacking happens in the proper order + var required_times = []; + if (scope.data.length > 1) { + required_times = Array.prototype.concat.apply([], _.map(scope.data, function (query) { + return query.time_series.getOrderedTimes(); + })); + required_times = _.uniq(required_times.sort(function (a, b) { + // decending numeric sort + return a-b; + }), true); + } + + for (var i = 0; i < scope.data.length; i++) { + scope.data[i].data = scope.data[i].time_series.getFlotPairs(required_times); + } + + // ISSUE: SOL-76 + // If 'lines_smooth' is enabled, loop through $scope.data[] and remove zero filled entries. + // Without zero values, the line chart will appear smooth as SiLK ;-) + if (scope.panel.lines_smooth) { + for (var i=0; i < scope.data.length; i++) { // jshint ignore: line + var new_data = []; + for (var j=0; j < scope.data[i].data.length; j++) { + // if value of the timestamp !== 0, then add it to new_data + if (scope.data[i].data[j][1] !== 0) { + new_data.push(scope.data[i].data[j]); + } + } + scope.data[i].data = new_data; + } + } + + scope.plot = $.plot(elem, scope.data, options); + } catch(e) { + // TODO: Need to fix bug => "Invalid dimensions for plot, width = 0, height = 200" + // console.log(e); + } + } + + function time_format(interval) { + var _int = kbn.interval_to_seconds(interval); + if(_int >= 2628000) { + return "%m/%y"; + } + if(_int >= 86400) { + return "%m/%d/%y"; + } + if(_int >= 60) { + return "%H:%M
%m/%d"; + } + + return "%H:%M:%S"; + } + + var $tooltip = $('
'); + elem.bind("plothover", function (event, pos, item) { + var group, value; + if (item) { + + if (scope.panel.stack && scope.panel.tooltip.value_type === 'individual') { + + value = item.datapoint[1] - item.datapoint[2]; + if(item.series.color=='#2ce41b'){ + value=item.datapoint[1]; + } + } else { + value = item.datapoint[1]; + } + + var lnLastValue = value; + + var lbPositiveValue = (lnLastValue>0); + + var isr = 0; + var lsItemTT = ""; + var lsTT =""; + if(lnLastValue!=0){ + if (item.series.info.alias.substring(0,item.series.info.alias.length-2) || scope.panel.tooltip.query_as_alias) { + group = '' + + '' + ' ' + + (item.series.info.alias.substring(0,item.series.info.alias.length-2) || item.series.info.query)+ + '
'; + } else { + group = kbn.query_color_dot(item.series.color, 15) + ' '; + } + lsItemTT = group + dashboard.numberWithCommas(value) + " @ " + (scope.panel.timezone === 'utc'? moment.utc(item.datapoint[0]).format('MM/DD HH:mm:ss') : moment(item.datapoint[0]).format('MM/DD HH:mm:ss')); + lsTT = lsItemTT; + isr =1; + } + + + var hoverSeries = item.series; + var x = item.datapoint[0]; + // y = item.datapoint[1]; + + + var allSeries = scope.plot.getData(); + var posSerie = -1; + + for (var i= allSeries.length - 1 ; i>=0; i--) { + + //if stack stop at the first positive value + if (scope.panel.stack && lbPositiveValue){ + break; + } + + var s = allSeries[i]; + i = parseInt(i); + + + if (s === hoverSeries ) { + posSerie = i; + } + + //not consider serie "upper" the hover serie + if ( i >= posSerie ){ + continue; + } + + //search in current serie a point with de same position. + for(var j= 0; j< s.data.length;j++){ + var p = s.data[j]; + if (p[0] === x ){ + + if (scope.panel.stack && scope.panel.tooltip.value_type === 'individual' && !isNaN(p[2])) { + value = p[1] - p[2]; + } else { + value = p[1]; + } + + lbPositiveValue = value > 0; + + if (! scope.panel.stack && value !== lnLastValue){ + break; + } + + posSerie = i; + lnLastValue = value; + + + + if(lnLastValue != 0){ + if (s.info.alias.substring(0,s.info.alias.length-2) || scope.panel.tooltip.query_as_alias) { + group = '' + + '' + ' ' + + (s.info.alias.substring(0,s.info.alias.length-2) || s.info.query)+ + '
'; + } else { + group = kbn.query_color_dot(s.color, 15) + ' '; + } + lsItemTT = group + dashboard.numberWithCommas(value) + " @ " + (scope.panel.timezone === 'utc'? moment.utc(p[0]).format('MM/DD HH:mm:ss') : moment(p[0]).format('MM/DD HH:mm:ss')); + lsTT = lsTT +"
"+ lsItemTT; + isr =1; + } + + break; + } + } + } + + if(isr){ + $tooltip + .html( lsTT ) + .place_tt(pos.pageX, pos.pageY); + } + } else { + $tooltip.detach(); + } + }); + + elem.bind("plotselected", function (event, ranges) { + + filterSrv.set({ + type: 'time', + // from : moment.utc(ranges.xaxis.from), + // to : moment.utc(ranges.xaxis.to), + from: moment.utc(ranges.xaxis.from).toDate(), + to: moment.utc(ranges.xaxis.to).toDate(), + field: filterSrv.getTimeField() + }); + dashboard.current.linkage_id = $scope.panel.linkage_id; + dashboard.current.enable_linkage = false; + dashboard.refresh(); + + }); + } + }; + }); + +}); diff --git a/src/app/panels/histogramt/timeSeries.js b/src/app/panels/histogramt/timeSeries.js new file mode 100644 index 000000000..96054fa7d --- /dev/null +++ b/src/app/panels/histogramt/timeSeries.js @@ -0,0 +1,179 @@ +define([ + 'underscore', + './interval' +], +function (_, Interval) { + 'use strict'; + + var ts = {}; + + // map compatable parseInt + function base10Int(val) { + return parseInt(val, 10); + } + + // trim the ms off of a time, but return it with empty ms. + function getDatesTime(date) { + return Math.floor(date.getTime() / 1000)*1000; + } + + /** + * Certain graphs require 0 entries to be specified for them to render + * properly (like the line graph). So with this we will caluclate all of + * the expected time measurements, and fill the missing ones in with 0 + * @param {object} opts An object specifying some/all of the options + * + * OPTIONS: + * @opt {string} interval The interval notion describing the expected spacing between + * each data point. + * @opt {date} start_date (optional) The start point for the time series, setting this and the + * end_date will ensure that the series streches to resemble the entire + * expected result + * @opt {date} end_date (optional) The end point for the time series, see start_date + * @opt {string} fill_style Either "minimal", or "all" describing the strategy used to zero-fill + * the series. + */ + ts.ZeroFilled = function (opts) { + opts = _.defaults(opts, { + interval: '10m', + start_date: null, + end_date: null, + fill_style: 'minimal' + }); + + // the expected differenece between readings. + this.interval = new Interval(opts.interval); + + // will keep all values here, keyed by their time + this._data = {}; + this.start_time = opts.start_date && getDatesTime(opts.start_date); + this.end_time = opts.end_date && getDatesTime(opts.end_date); + this.opts = opts; + }; + + /** + * Add a row + * @param {int} time The time for the value, in + * @param {any} value The value at this time + */ + ts.ZeroFilled.prototype.addValue = function (time, value) { + if (time instanceof Date) { + time = getDatesTime(time); + } else { + time = base10Int(time); + } + if (!isNaN(time)) { + this._data[time] = (_.isUndefined(value) ? 0 : value); + } + this._cached_times = null; + }; + + /** + * Get an array of the times that have been explicitly set in the series + * @param {array} include (optional) list of timestamps to include in the response + * @return {array} An array of integer times. + */ + ts.ZeroFilled.prototype.getOrderedTimes = function (include) { + var times = _.map(_.keys(this._data), base10Int); + if (_.isArray(include)) { + times = times.concat(include); + } + return _.uniq(times.sort(function (a, b) { + // decending numeric sort + return a - b; + }), true); + }; + + /** + * return the rows in the format: + * [ [time, value], [time, value], ... ] + * + * Heavy lifting is done by _get(Min|All)FlotPairs() + * @param {array} required_times An array of timestamps that must be in the resulting pairs + * @return {array} + */ + ts.ZeroFilled.prototype.getFlotPairs = function (required_times) { + var times = this.getOrderedTimes(required_times), + strategy, + pairs; + + if(this.opts.fill_style === 'all') { + strategy = this._getAllFlotPairs; + } else { + strategy = this._getMinFlotPairs; + } + + pairs = _.reduce( + times, // what + strategy, // how + [], // where + this // context + ); + + // if the first or last pair is inside either the start or end time, + // add those times to the series with null values so the graph will stretch to contain them. + if (this.start_time && (pairs.length === 0 || pairs[0][0] > this.start_time)) { + pairs.unshift([this.start_time, null]); + } + if (this.end_time && (pairs.length === 0 || pairs[pairs.length - 1][0] < this.end_time)) { + pairs.push([this.end_time, null]); + } + + return pairs; + }; + + /** + * ** called as a reduce stragegy in getFlotPairs() ** + * Fill zero's on either side of the current time, unless there is already a measurement there or + * we are looking at an edge. + * @return {array} An array of points to plot with flot + */ + ts.ZeroFilled.prototype._getMinFlotPairs = function (result, time, i, times) { + var next, expected_next, prev, expected_prev; + + // check for previous measurement + if (i > 0) { + prev = times[i - 1]; + expected_prev = this.interval.before(time); + if (prev < expected_prev) { + result.push([expected_prev, 0]); + } + } + + // add the current time + result.push([ time, this._data[time] || 0 ]); + + // check for next measurement + if (times.length > i) { + next = times[i + 1]; + expected_next = this.interval.after(time); + if (next > expected_next) { + result.push([expected_next, 0]); + } + } + + return result; + }; + + /** + * ** called as a reduce stragegy in getFlotPairs() ** + * Fill zero's to the right of each time, until the next measurement is reached or we are at the + * last measurement + * @return {array} An array of points to plot with flot + */ + ts.ZeroFilled.prototype._getAllFlotPairs = function (result, time, i, times) { + var next, expected_next; + + result.push([ times[i], this._data[times[i]] || 0 ]); + next = times[i + 1]; + expected_next = this.interval.after(time); + for(; times.length > i && next > expected_next; expected_next = this.interval.after(expected_next)) { + result.push([expected_next, 0]); + } + + return result; + }; + + + return ts; +}); \ No newline at end of file diff --git a/src/app/panels/histoline/editor.html b/src/app/panels/histoline/editor.html new file mode 100644 index 000000000..55319a806 --- /dev/null +++ b/src/app/panels/histoline/editor.html @@ -0,0 +1,111 @@ +
+
+ + + + +
+
+ + +
+
+ + +
+
+ + +
+ + +
+ + +
+
+ In {{panel.mode}} mode the configured field must be a numeric type. +
+
+ + +
+
+ +
+
+ +
+
+
+ +
+
+ +
+ + +
+
+ + +
+ + +
+ + +
+ + + +
+ + + +
Chart Settings
+ + + + +
+ + +
+ +
+
+ +
+
+ + +
+
+ + +
+ +
+ +
Tooltip Settings
+
+
+ + +
+
+ + +
+
+
+
Linkage Effective
+
+ +
+ +
diff --git a/src/app/panels/histoline/interval.js b/src/app/panels/histoline/interval.js new file mode 100644 index 000000000..673371fcf --- /dev/null +++ b/src/app/panels/histoline/interval.js @@ -0,0 +1,57 @@ +define([ + 'kbn' +], +function (kbn) { + 'use strict'; + + /** + * manages the interval logic + * @param {[type]} interval_string An interval string in the format '1m', '1y', etc + */ + function Interval(interval_string) { + this.string = interval_string; + + var info = kbn.describe_interval(interval_string); + this.type = info.type; + this.ms = info.sec * 1000 * info.count; + + // does the length of the interval change based on the current time? + if (this.type === 'y' || this.type === 'M') { + // we will just modify this time object rather that create a new one constantly + this.get = this.get_complex; + this.date = new Date(0); + } else { + this.get = this.get_simple; + } + } + + Interval.prototype = { + toString: function () { + return this.string; + }, + after: function(current_ms) { + return this.get(current_ms, 1); + }, + before: function (current_ms) { + return this.get(current_ms, -1); + }, + get_complex: function (current, delta) { + this.date.setTime(current); + switch(this.type) { + case 'M': + this.date.setUTCMonth(this.date.getUTCMonth() + delta); + break; + case 'y': + this.date.setUTCFullYear(this.date.getUTCFullYear() + delta); + break; + } + return this.date.getTime(); + }, + get_simple: function (current, delta) { + return current + (delta * this.ms); + } + }; + + return Interval; + +}); \ No newline at end of file diff --git a/src/app/panels/histoline/module.html b/src/app/panels/histoline/module.html new file mode 100644 index 000000000..9128ca9c9 --- /dev/null +++ b/src/app/panels/histoline/module.html @@ -0,0 +1,133 @@ +
+ + + +
+
+ + + View + + +
+ + + + + + + + + + + + + +
+ +
+
+ + + + + + +
{{term.label}}{{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}
+ + +
+ {{term.label}} ({{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}) +

+ +
+
{{data.length - 2}}
+ +
+ +
+ + + + + + +
{{term.label}}{{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}
+
+ +
+ +
+ + + + + + +
{{term.label}}{{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}
+ + +
+ {{term.label}} ({{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}) +

+ +
+ + + + + + +
+
+
diff --git a/src/app/panels/histoline/module.js b/src/app/panels/histoline/module.js new file mode 100644 index 000000000..15aa4eaa1 --- /dev/null +++ b/src/app/panels/histoline/module.js @@ -0,0 +1,679 @@ +/* + + ## Histogram + + ### Parameters + * auto_int :: Auto calculate data point interval? + * resolution :: If auto_int is enables, shoot for this many data points, rounding to + sane intervals + * interval :: Datapoint interval in elasticsearch date math format (eg 1d, 1w, 1y, 5y) + * fill :: Only applies to line charts. Level of area shading from 0-10 + * linewidth :: Only applies to line charts. How thick the line should be in pixels + While the editor only exposes 0-10, this can be any numeric value. + Set to 0 and you'll get something like a scatter plot + * timezone :: This isn't totally functional yet. Currently only supports browser and utc. + browser will adjust the x-axis labels to match the timezone of the user's + browser + * spyable :: Dislay the 'eye' icon that show the last elasticsearch query + * zoomlinks :: Show the zoom links? + * bars :: Show bars in the chart + * stack :: Stack multiple queries. This generally a crappy way to represent things. + You probably should just use a line chart without histoline + * points :: Should circles at the data points on the chart + * lines :: Line chart? Sweet. + * legend :: Show the legend? + * x-axis :: Show x-axis labels and grid lines + * y-axis :: Show y-axis labels and grid lines + * interactive :: Allow drag to select time range + +*/ +define([ + 'angular', + 'app', + 'jquery', + 'underscore', + 'kbn', + 'moment', + './timeSeries' + + +], +function (angular, app, $, _, kbn, moment, timeSeries) { + 'use strict'; + + var module = angular.module('kibana.panels.histoline', []); + app.useModule(module); + + module.controller('histoline', function($scope, $q, querySrv, dashboard, filterSrv) { + var _d; + $scope.panelMeta = { + + editorTabs : [ + { + title:'Queries', + src:'app/partials/querySelect.html' + } + ], + status : "Stable", + description : "A bucketed time series chart of the current query, including all applied time and non-time filters, when used in count mode. Uses Solr’s facet.range query parameters. In values mode, it plots the value of a specific field over time, and allows the user to group field values by a second field." + }; + + // Set and populate defaults + _d = { + mode: 'value', + queries: { + mode: 'all', + ids: [], + query: '*:*', + custom: '' + }, + max_rows: 100000, // maximum number of rows returned from Solr (also use this for group.limit to simplify UI setting) + reverse: 0, + segment: 4, + display:'block', + icon:"icon-caret-down", + threshold_first: 300, + threshold_second: 400, + threshold_third: 3000, + group_field: null, + linkage_id:'a', + auto_int: true, + area:false, + total_first: '%', + fontsize: 12, + field_color: '#2ce41b', + resolution: 100, + value_sort: 'rs_timestamp', + interval: '5m', + intervals: ['auto', '1s', '1m', '5m', '10m', '30m', '1h', '3h', '12h', '1d', '1w', '1M', '1y'], + fill: 0, + linewidth: 3, + chart: 'histoline', + chartColors: ['#f48a52', '#f4d352', '#ccf452', '#8cf452', '#3cee2b', '#f467d8', '#1a93f9', '#2fd7ee'], + timezone: 'browser', // browser, utc or a standard timezone + spyable: true, + linkage: false, + zoomlinks: true, + bars: true, + average: false, + label: true, + points: false, + lines: false, + lines_smooth: false, // Enable 'smooth line' mode by removing zero values from the plot. + legend: true, + 'x-axis': true, + 'y-axis': true, + percentage: false, + interactive: true, + options: false, + show_queries: true, + tooltip: { + value_type: 'cumulative', + query_as_alias: false + } + }; + + _.defaults($scope.panel,_d); + + $scope.init = function() { + // Hide view options by default + $scope.options = false; + $scope.$on('refresh',function(){ + $scope.get_data(); + }); + + $scope.get_data(); + + }; + $scope.display=function() { + if($scope.panel.display==='none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; + $scope.set_interval = function(interval) { + if(interval !== 'auto') { + $scope.panel.auto_int = false; + $scope.panel.interval = interval; + } else { + $scope.panel.auto_int = true; + } + }; + + $scope.interval_label = function(interval) { + return $scope.panel.auto_int && interval === $scope.panel.interval ? interval+" (auto)" : interval; + }; + + /** + * The time range effecting the panel + * @return {[type]} [description] + */ + $scope.get_time_range = function () { + var range = $scope.range = filterSrv.timeRange('min'); + return range; + }; + + $scope.get_interval = function () { + var interval = $scope.panel.interval, + range; + if ($scope.panel.auto_int) { + range = $scope.get_time_range(); + if (range) { + interval = kbn.secondsToHms( + kbn.calculate_interval(range.from, range.to, $scope.panel.resolution, 0) / 1000 + ); + } + } + $scope.panel.interval = interval || '10m'; + return $scope.panel.interval; + }; + + /** + * Fetch the data for a chunk of a queries results. Multiple segments occur when several indicies + * need to be consulted (like timestamped logstash indicies) + * + * The results of this function are stored on the scope's data property. This property will be an + * array of objects with the properties info, time_series, and hits. These objects are used in the + * render_panel function to create the historgram. + * + * !!! Solr does not need to fetch the data in chunk because it uses a facet search and retrieve + * !!! all events from a single query. + * + * @param {number} segment The segment count, (0 based) + * @param {number} query_id The id of the query, generated on the first run and passed back when + * this call is made recursively for more segments + */ + $scope.get_data = function(segment, query_id) { + if(($scope.panel.linkage_id===dashboard.current.linkage_id)||dashboard.current.enable_linkage){ + if (_.isUndefined(segment)) { + segment = 0; + } + delete $scope.panel.error; + + // Make sure we have everything for the request to complete + if (dashboard.indices.length === 0) { + return; + } + var _range = $scope.get_time_range(); + var _interval = $scope.get_interval(_range); + + if ($scope.panel.auto_int) { + $scope.panel.interval = kbn.secondsToHms( + kbn.calculate_interval(_range.from, _range.to, $scope.panel.resolution, 0) / 1000); + } + + $scope.panelMeta.loading = true; + + // Solr + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + var request = $scope.sjs.Request().indices(dashboard.indices[segment]); + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + + + $scope.panel.queries.query = ""; + // Build the query + _.each($scope.panel.queries.ids, function (id) { + var query = $scope.sjs.FilteredQuery( + querySrv.getEjsObj(id), + filterSrv.getBoolFilter(filterSrv.ids) + ); + + var facet = $scope.sjs.DateHistogramFacet(id); + if ($scope.panel.mode === 'count' || $scope.panel.mode === 'counts') { + facet = facet.field(filterSrv.getTimeField()); + } else { + if (_.isNull($scope.panel.value_field)) { + $scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified"; + return; + } + facet = facet.keyField(filterSrv.getTimeField()).valueField($scope.panel.value_field); + } + facet = facet.interval(_interval).facetFilter($scope.sjs.QueryFilter(query)); + request = request.facet(facet).size(0); + + }); + + // Populate the inspector panel + $scope.populate_modal(request); + + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + } + var time_field = filterSrv.getTimeField(); + var start_time = filterSrv.getStartTime(); + var end_time = filterSrv.getEndTime(); + + // facet.range.end does NOT accept * as a value, need to convert it to NOW + if (end_time === '*') { + end_time = 'NOW'; + } + + var wt_json = '&wt=json'; + var sort_s = '&sort=' + $scope.panel.value_sort + '%20asc'; + var rows_limit = '&rows=0'; // for histogram, we do not need the actual response doc, so set rows=0 + var facet_gap = $scope.sjs.convertFacetGap($scope.panel.interval); + var facet = '&facet=true' + + '&facet.range=' + time_field + + '&facet.range.start=' + start_time + + '&facet.range.end=' + end_time + + '&facet.range.gap=' + facet_gap; + var values_mode_query = ''; + + // For mode = value + if ($scope.panel.mode === 'values' || $scope.panel.mode === 'value') { + if (!$scope.panel.value_field) { + $scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified"; + return; + } + values_mode_query = '&fl=' + time_field + ' ' + $scope.panel.value_field; + + rows_limit = '&rows=' + $scope.panel.max_rows; + facet = ''; + + // if Group By Field is specified + if ($scope.panel.group_field) { + values_mode_query += '&group=true&group.field=' + $scope.panel.group_field + '&group.limit=' + $scope.panel.max_rows; + } + } + + var mypromises = []; + + if ($scope.panel.mode === 'value' || $scope.panel.mode === 'counts') { + var arr_id = [0]; + _.each(arr_id, function () { + var temp_q = 'q=' + $scope.panel.value_field + '%3A%5B' + '*' + '%20TO%20' + '*' + '%5D' + wt_json + sort_s + rows_limit + fq + facet + values_mode_query; + + $scope.panel.queries.query += temp_q + "\n"; + if ($scope.panel.queries.custom !== null) { + request = request.setQuery(temp_q + $scope.panel.queries.custom); + } else { + request = request.setQuery(temp_q); + } + mypromises.push(request.doSearch()); + }); + } + $scope.data = []; + + if (dashboard.current.services.query.ids.length >= 1) { + $q.all(mypromises).then(function (results) { + $scope.panelMeta.loading = false; + if (segment === 0) { + $scope.hits = 0; + $scope.data = []; + query_id = $scope.query_id = new Date().getTime(); + } + // Convert facet ids to numbers + // var facetIds = _.map(_.keys(results.facets),function(k){return parseInt(k, 10);}); + //var facetIds = [0]; // Need to fix this + + // Make sure we're still on the same query/queries + // TODO: We probably DON'T NEED THIS unless we have to support multiple queries in query module. + // if ($scope.query_id === query_id && _.difference(facetIds, $scope.panel.queries.ids).length === 0) { + var i = 0, + time_series, + hits; + + _.each(arr_id, function (id, index) { + // Check for error and abort if found + if (!(_.isUndefined(results[index].error))) { + $scope.panel.error = $scope.parse_error(results[index].error.msg); + return; + } + // we need to initialize the data variable on the first run, + // and when we are working on the first segment of the data. + if (_.isUndefined($scope.data[i]) || segment === 0) { + time_series = new timeSeries.ZeroFilled({ + interval: _interval, + start_date: _range && _range.from, + end_date: _range && _range.to, + fill_style: 'minimal' + }); + hits = 0; + } else { + time_series = $scope.data[i].time_series; + // Bug fix for wrong event count: + // Solr don't need to accumulate hits count since it can get total count from facet query. + // Therefore, I need to set hits and $scope.hits to zero. + // hits = $scope.data[i].hits; + hits = 0; + $scope.hits = 0; + } + + // Solr facet counts response is in one big array. + // So no need to get each segment like Elasticsearch does. + + $scope.data[i] = results[index].response.docs; + + + i++; + }); + + // Tell the histogram directive to render. + $scope.$emit('render'); + // } + }); + } + + } + }; + + // function $scope.zoom + // factor :: Zoom factor, so 0.5 = cuts timespan in half, 2 doubles timespan + $scope.zoom = function(factor) { + var _range = filterSrv.timeRange('min'); + var _timespan = (_range.to.valueOf() - _range.from.valueOf()); + var _center = _range.to.valueOf() - _timespan/2; + + var _to = (_center + (_timespan*factor)/2); + var _from = (_center - (_timespan*factor)/2); + + // If we're not already looking into the future, don't. + if(_to > Date.now() && _range.to < Date.now()) { + var _offset = _to - Date.now(); + _from = _from - _offset; + _to = Date.now(); + } + + var time_field = filterSrv.getTimeField(); + if(factor > 1) { + filterSrv.removeByType('time'); + } + + filterSrv.set({ + type:'time', + from:moment.utc(_from).toDate(), + to:moment.utc(_to).toDate(), + field:time_field + }); + + dashboard.refresh(); + }; + + // I really don't like this function, too much dom manip. Break out into directive? + $scope.populate_modal = function(request) { + $scope.inspector = angular.toJson(JSON.parse(request.toString()),true); + }; + + $scope.set_refresh = function (state) { + $scope.refresh = state; + }; + + $scope.close_edit = function() { + if($scope.refresh) { + $scope.get_data(); + } + $scope.refresh = false; + $scope.$emit('render'); + }; + + $scope.render = function() { + $scope.$emit('render'); + }; + + }); + + module.directive('histolineChart', function(querySrv,dashboard,filterSrv) { + return { + restrict: 'A', + link: function(scope, elem) { + var myChart; + // Receive render events + scope.$on('render',function(){ + render_panel(); + }); + + // Re-render if the window is resized + angular.element(window).bind('resize', function(){ + render_panel(); + }); + + // Function for rendering panel + function render_panel() { + var chartData; + var colors = []; + + // IE doesn't work without this + elem.css({height:scope.panel.height||scope.row.height}); + + // Make a clone we can operate on. + + chartData = _.clone(scope.data); + chartData = scope.panel.missing ? chartData : + _.without(chartData,_.findWhere(chartData,{meta:'missing'})); + chartData = scope.panel.other ? chartData : + _.without(chartData,_.findWhere(chartData,{meta:'other'})); + + if (filterSrv.idsByTypeAndField('terms',scope.panel.field).length > 0) { + colors.push(scope.panel.lastColor); + } else { + colors = scope.panel.chartColors; + } + var selecttime = []; + + var secondtime ; + var maxdata= 0; + var sum_data = 0; + var sum_normal = 0; + var sum_risk = 0; + var sum_warning = 0; + var xAxis = [], + yAxis = [], + data = [], + series = [], + seriesItem; + for (var i =0;iscope.panel.threshold_second){ + sum_risk++; + name_c ='Risk'; + color_c = '#ec4653'; + // valuedata[i] ={name:"Risk",value:chartData[0][i][scope.panel.value_field],itemStyle:{normal:{color:'#c55249'}}}; + }else if(chartData[0][i][scope.panel.value_field] this.start_time)) { + pairs.unshift([this.start_time, null]); + } + if (this.end_time && (pairs.length === 0 || pairs[pairs.length - 1][0] < this.end_time)) { + pairs.push([this.end_time, null]); + } + + return pairs; + }; + + /** + * ** called as a reduce stragegy in getFlotPairs() ** + * Fill zero's on either side of the current time, unless there is already a measurement there or + * we are looking at an edge. + * @return {array} An array of points to plot with flot + */ + ts.ZeroFilled.prototype._getMinFlotPairs = function (result, time, i, times) { + var next, expected_next, prev, expected_prev; + + // check for previous measurement + if (i > 0) { + prev = times[i - 1]; + expected_prev = this.interval.before(time); + if (prev < expected_prev) { + result.push([expected_prev, 0]); + } + } + + // add the current time + result.push([ time, this._data[time] || 0 ]); + + // check for next measurement + if (times.length > i) { + next = times[i + 1]; + expected_next = this.interval.after(time); + if (next > expected_next) { + result.push([expected_next, 0]); + } + } + + return result; + }; + + /** + * ** called as a reduce stragegy in getFlotPairs() ** + * Fill zero's to the right of each time, until the next measurement is reached or we are at the + * last measurement + * @return {array} An array of points to plot with flot + */ + ts.ZeroFilled.prototype._getAllFlotPairs = function (result, time, i, times) { + var next, expected_next; + + result.push([ times[i], this._data[times[i]] || 0 ]); + next = times[i + 1]; + expected_next = this.interval.after(time); + for(; times.length > i && next > expected_next; expected_next = this.interval.after(expected_next)) { + result.push([expected_next, 0]); + } + + return result; + }; + + + return ts; +}); \ No newline at end of file diff --git a/src/app/panels/hits/editor.html b/src/app/panels/hits/editor.html old mode 100755 new mode 100644 index 28d9bed5d..0cf399ebc --- a/src/app/panels/hits/editor.html +++ b/src/app/panels/hits/editor.html @@ -1,89 +1,55 @@ -
- The panel needs to have at least one metric. For each metric, you can select a different type of stats to be shown. - Decimal Digit is the number of digits to display after the decimal point. And you can specify your own Label for - each metric (optional). Not all stats are supported for all field types. Check Solr documentation for details. -
- -
- -
- -
-
- - - - - - - - - - - - - - -
Stats TypeField Not all statistics are supported for all field types. Check Solr documentation for details.Decimal Digits The number of digits to display after the decimal point.Label
- - - - - - - - - -
+
+
+
+ + +
- -
- -
- - - - -
- - + +
- - - - - - - - - - - - - - - - - - - -
- -
-
Real-time (Auto-refresh)
-
- +
+ + +
+
+ + +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
-
- - +
+ +
+
+ + +
+
+ + +
+
+
+
+
Linkage Effective
+
+ +
+
diff --git a/src/app/panels/hits/module.html b/src/app/panels/hits/module.html old mode 100755 new mode 100644 index 0bf23d71b..d8bfd2809 --- a/src/app/panels/hits/module.html +++ b/src/app/panels/hits/module.html @@ -1,80 +1,46 @@
- - -
- - - - - - - -
-
-
{{query.info.alias}}{{query.data[0][1]}}
+
+
+ + + + + +
{{query.info.alias}}{{query.data[0][1]}}
- -
- {{query.info.alias}} ({{query.data[0][1]}}) -
-
+ +
+ {{query.info.alias}} ({{query.data[0][1]}}) +

-
- -
- -
+
-
- - - - - - - -
{{query.info.alias}}{{query.data[0][1]}}
+
- -
- {{query.info.alias}} - ({{query.data[0][1]}}) -
-
+
-
+
+ + + + + +
{{query.info.alias}}{{query.data[0][1]}}
- -
- - - - + +
+ {{query.info.alias}} ({{query.data[0][1]}}) +

-
-
{{dashboard.numberWithCommas(metric.value)}}
-
{{metric.label}}
-
+
-
+
{{dashboard.numberWithCommas(hits)}}
- -
+ +
{{query.info.alias}} ({{query.hits}})
-

+
+
diff --git a/src/app/panels/hits/module.js b/src/app/panels/hits/module.js old mode 100755 new mode 100644 index 46e82f912..0295b9950 --- a/src/app/panels/hits/module.js +++ b/src/app/panels/hits/module.js @@ -1,130 +1,91 @@ /* - ## Hits + ## Hits - ### Parameters - * style :: A hash of css styles - * arrangement :: How should I arrange the query results? 'horizontal' or 'vertical' - * chart :: Show a chart? 'none', 'bar', 'pie' - * donut :: Only applies to 'pie' charts. Punches a hole in the chart for some reason - * tilt :: Only 'pie' charts. Janky 3D effect. Looks terrible 90% of the time. - * lables :: Only 'pie' charts. Labels on the pie? + ### Parameters + * style :: A hash of css styles + * arrangement :: How should I arrange the query results? 'horizontal' or 'vertical' + * chart :: Show a chart? 'none', 'bar', 'pie' + * donut :: Only applies to 'pie' charts. Punches a hole in the chart for some reason + * tilt :: Only 'pie' charts. Janky 3D effect. Looks terrible 90% of the time. + * lables :: Only 'pie' charts. Labels on the pie? - */ +*/ define([ - 'angular', - 'app', - 'underscore', - 'jquery', - 'kbn', - - 'jquery.flot', - 'jquery.flot.pie' + 'angular', + 'app', + 'underscore', + 'jquery', + 'kbn', + + 'jquery.flot', + 'jquery.flot.pie' ], function (angular, app, _, $, kbn) { - 'use strict'; - - var module = angular.module('kibana.panels.hits', []); - app.useModule(module); - - module.controller('hits', function ($scope, $q, $timeout, timer, querySrv, dashboard, filterSrv) { - $scope.panelMeta = { - modals: [{ - description: "Inspect", - icon: "icon-info-sign", - partial: "app/partials/inspector.html", - show: $scope.panel.spyable - }], - editorTabs: [{ - title: 'Queries', - src: 'app/partials/querySelect.html' - }], - status: "Stable", - description: "Showing stats like count, min, max, and etc. for the current query including all the applied filters." - }; - - function Metric() { - this.type = 'count'; // Stats type - this.field = ''; // Stats field - this.decimalDigits = 2; - this.label = ''; - this.value = 0; - } - - // Set and populate defaults - var _d = { - queries: { - mode: 'all', - ids: [], - query: '*:*', - basic_query: '', - custom: '' - }, - style: {"font-size": '10pt'}, - arrangement: 'horizontal', - chart: 'total', - counter_pos: 'above', - donut: false, - tilt: false, - labels: true, - spyable: true, - show_queries: true, - metrics: [new Metric()], - refresh: { - enable: false, - interval: 2 - } - }; - _.defaults($scope.panel, _d); - - $scope.init = function () { - $scope.hits = 0; - - // Start refresh timer if enabled - if ($scope.panel.refresh.enable) { - $scope.set_timer($scope.panel.refresh.interval); - } - - $scope.$on('refresh', function () { - $scope.get_data(); - }); - - $scope.get_data(); - }; - - $scope.set_timer = function (refresh_interval) { - $scope.panel.refresh.interval = refresh_interval; - if (_.isNumber($scope.panel.refresh.interval)) { - timer.cancel($scope.refresh_timer); - $scope.realtime(); - } else { - timer.cancel($scope.refresh_timer); - } - }; - - $scope.realtime = function () { - if ($scope.panel.refresh.enable) { - timer.cancel($scope.refresh_timer); - - $scope.refresh_timer = timer.register($timeout(function () { - $scope.realtime(); - $scope.get_data(); - }, $scope.panel.refresh.interval * 1000)); - } else { - timer.cancel($scope.refresh_timer); - } - }; - - $scope.addMetric = function () { - $scope.panel.metrics.push(new Metric()); - }; - - $scope.removeMetric = function (metric) { - if ($scope.panel.metrics.length > 1) { - $scope.panel.metrics = _.without($scope.panel.metrics, metric); - } - }; - - $scope.get_data = function () { + 'use strict'; + + var module = angular.module('kibana.panels.hits', []); + app.useModule(module); + + module.controller('hits', function($scope, $q, querySrv, dashboard, filterSrv) { + $scope.panelMeta = { + + editorTabs : [ + {title:'Queries', src:'app/partials/querySelect.html'} + ], + status : "Stable", + description : "The total hits for the current query including all the applied filters." + }; + + // Set and populate defaults + var _d = { + queries : { + mode : 'all', + ids : [], + query : '*:*', + basic_query : '', + custom : '' + }, + style : { "font-size": '10pt'}, + arrangement : 'horizontal', + chart : 'total', + counter_pos : 'above', + donut : false, + linkage_id:'a', + tilt : false, + display:'block', + icon:"icon-caret-down", + labels : true, + spyable : true, + show_queries:true, + show_stats: false, + stats_type : 'mean', + stats_field : '', + stats_decimal_points : 2 + }; + _.defaults($scope.panel,_d); + + $scope.init = function () { + $scope.hits = 0; + + $scope.$on('refresh',function(){ + $scope.get_data(); + }); + $scope.get_data(); + + }; + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; + $scope.get_data = function() { + if(($scope.panel.linkage_id === dashboard.current.linkage_id)||dashboard.current.enable_linkage) { delete $scope.panel.error; $scope.panelMeta.loading = true; @@ -135,9 +96,10 @@ define([ // Solr $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + var request = $scope.sjs.Request().indices(dashboard.indices); - $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); // Build the question part of the query _.each($scope.panel.queries.ids, function (id) { var _q = $scope.sjs.FilteredQuery( @@ -158,14 +120,11 @@ define([ if (filterSrv.getSolrFq()) { fq = '&' + filterSrv.getSolrFq(); } - - var stats = '&stats=true'; - _.each($scope.panel.metrics, function(metric) { - if (metric.field) { - stats += '&stats.field=' + metric.field; - } - }); - + // if Show Stats + var stats = ''; + if ($scope.panel.show_stats) { + stats = '&stats=true&stats.field=' + $scope.panel.stats_field; + } var wt_json = '&wt=json'; var rows_limit = '&rows=0'; // for hits, we do not need the actual response doc, so set rows=0 var promises = []; @@ -190,13 +149,17 @@ define([ _.each(dashboard.current.services.query.ids, function (id, i) { $scope.panelMeta.loading = false; - _.each(results[i].stats.stats_fields, function(metricValues, metricField) { - _.each($scope.panel.metrics, function(metric) { - if (metric.field === metricField) { - metric.value = metricValues[metric.type].toFixed(metric.decimalDigits); - } - }); - }); + var result_value; + + // check what value to show, either total count or stats + if (!$scope.panel.show_stats) { + result_value = results[i].response.numFound; + $scope.hits += results[i].response.numFound; + } else { + result_value = results[i].stats.stats_fields[$scope.panel.stats_field][$scope.panel.stats_type]; + $scope.hits += results[i].stats.stats_fields[$scope.panel.stats_field][$scope.panel.stats_type]; + $scope.hits = $scope.hits.toFixed($scope.panel.stats_decimal_points); + } // Check for error and abort if found if (!(_.isUndefined(results[i].error))) { @@ -204,143 +167,146 @@ define([ return; } - // var info = dashboard.current.services.query.list[id]; + var info = dashboard.current.services.query.list[id]; + // Create series - // $scope.data[i] = { - // info: info, - // id: id, - // hits: result_value, - // data: [[id, result_value]] - // }; + $scope.data[i] = { + info: info, + id: id, + hits: result_value, + data: [[id, result_value]] + }; $scope.$emit('render'); }); }); - }; - - $scope.set_refresh = function (state) { - $scope.refresh = state; - }; - - $scope.close_edit = function () { - // Start refresh timer if enabled - if ($scope.panel.refresh.enable) { - $scope.set_timer($scope.panel.refresh.interval); - } - if ($scope.refresh) { - $scope.get_data(); + } + }; + + $scope.set_refresh = function (state) { + $scope.refresh = state; + // if not show_stats, set stats_decimal_points to zero automatically. + if (!$scope.panel.show_stats) { + $scope.panel.stats_decimal_points = 0; + } + }; + + $scope.close_edit = function() { + if($scope.refresh) { + $scope.get_data(); + } + $scope.refresh = false; + $scope.$emit('render'); + }; + + $scope.populate_modal = function(request) { + $scope.inspector = angular.toJson(JSON.parse(request.toString()), true); + }; + + }); + + + module.directive('hitsChart', function(querySrv) { + return { + restrict: 'A', + link: function(scope, elem) { + + // Receive render events + scope.$on('render',function(){ + render_panel(); + }); + + // Re-render if the window is resized + angular.element(window).bind('resize', function(){ + render_panel(); + }); + + // Function for rendering panel + function render_panel() { + // IE doesn't work without this + elem.css({height:scope.panel.height||scope.row.height}); + + try { + _.each(scope.data, function(series) { + series.label = series.info.alias; + series.color = series.info.color; + }); + } catch(e) {return;} + + // Populate element + try { + // Add plot to scope so we can build out own legend + if (scope.panel.chart === 'bar') { + scope.plot = $.plot(elem, scope.data, { + legend: { show: false }, + series: { + lines: { show: false, }, + bars: { show: true, fill: 1, barWidth: 0.8, horizontal: false }, + shadowSize: 1 + }, + yaxis: { show: true, min: 0, color: "#c8c8c8" }, + xaxis: { show: false }, + grid: { + borderWidth: 0, + borderColor: '#eee', + color: "#eee", + hoverable: true, + }, + colors: querySrv.colors + }); } - $scope.refresh = false; - $scope.$emit('render'); - }; - - $scope.populate_modal = function (request) { - $scope.inspector = angular.toJson(JSON.parse(request.toString()), true); - }; - }); - - module.directive('hitsChart', function (querySrv) { - return { - restrict: 'A', - link: function (scope, elem) { - - // Receive render events - scope.$on('render', function () { - render_panel(); - }); - // Re-render if the window is resized - angular.element(window).bind('resize', function () { - render_panel(); - }); - - // Function for rendering panel - function render_panel() { - // IE doesn't work without this - elem.css({height: scope.panel.height || scope.row.height}); - - try { - _.each(scope.data, function (series) { - series.label = series.info.alias; - series.color = series.info.color; - }); - } catch (e) { - return; - } - - // Populate element - try { - // Add plot to scope so we can build out own legend - if (scope.panel.chart === 'bar') { - scope.plot = $.plot(elem, scope.data, { - legend: {show: false}, - series: { - lines: {show: false,}, - bars: {show: true, fill: 1, barWidth: 0.8, horizontal: false}, - shadowSize: 1 - }, - yaxis: {show: true, min: 0, color: "#c8c8c8"}, - xaxis: {show: false}, - grid: { - borderWidth: 0, - borderColor: '#eee', - color: "#eee", - hoverable: true, - }, - colors: querySrv.colors - }); - } - - if (scope.panel.chart === 'pie') { - scope.plot = $.plot(elem, scope.data, { - legend: {show: false}, - series: { - pie: { - innerRadius: scope.panel.donut ? 0.4 : 0, - tilt: scope.panel.tilt ? 0.45 : 1, - radius: 1, - show: true, - combine: { - color: '#999', - label: 'The Rest' - }, - stroke: { - width: 0 - }, - label: { - show: scope.panel.labels, - radius: 2 / 3, - formatter: function (label, series) { - return '
' + - label + '
' + Math.round(series.percent) + '%
'; - }, - threshold: 0.1 - } - } - }, - //grid: { hoverable: true, clickable: true }, - grid: {hoverable: true, clickable: true}, - colors: querySrv.colors - }); - } - } catch (e) { - elem.text(e); + if (scope.panel.chart === 'pie') { + scope.plot = $.plot(elem, scope.data, { + legend: { show: false }, + series: { + pie: { + innerRadius: scope.panel.donut ? 0.4 : 0, + tilt: scope.panel.tilt ? 0.45 : 1, + radius: 1, + show: true, + combine: { + color: '#999', + label: 'The Rest' + }, + stroke: { + width: 0 + }, + label: { + show: scope.panel.labels, + radius: 2/3, + formatter: function(label, series){ + return '
'+ + label+'
'+Math.round(series.percent)+'%
'; + }, + threshold: 0.1 } - } - - var $tooltip = $('
'); - elem.bind("plothover", function (event, pos, item) { - if (item) { - var value = scope.panel.chart === 'bar' ? - item.datapoint[1] : item.datapoint[1][0][1]; - $tooltip - .html(kbn.query_color_dot(item.series.color, 20) + ' ' + value.toFixed(0)) - .place_tt(pos.pageX, pos.pageY); - } else { - $tooltip.remove(); - } - }); + } + }, + //grid: { hoverable: true, clickable: true }, + grid: { hoverable: true, clickable: true }, + colors: querySrv.colors + }); } - }; - }); + } catch(e) { + elem.text(e); + } + } + + var $tooltip = $('
'); + elem.bind("plothover", function (event, pos, item) { + if (item) { + var value = scope.panel.chart === 'bar' ? + item.datapoint[1] : item.datapoint[1][0][1]; + $tooltip + .html(kbn.query_color_dot(item.series.color, 20) + ' ' + value.toFixed(0)) + .place_tt(pos.pageX, pos.pageY); + } else { + $tooltip.remove(); + } + }); + + } + }; + }); }); diff --git a/src/app/panels/map/editor.html b/src/app/panels/map/editor.html old mode 100755 new mode 100644 index 2deb8f030..09cbd3fcd --- a/src/app/panels/map/editor.html +++ b/src/app/panels/map/editor.html @@ -10,7 +10,7 @@
Max Maximum countries to plot
Map
- +
@@ -18,7 +18,7 @@
Max Maximum countries to plot
-
+
@@ -28,10 +28,18 @@
Max Maximum countries to plot
-
+
Country Names Coutry Names in the World Map would be detected, if checked
+
+
Linkage Effective
+
+ +
+ +
+ diff --git a/src/app/panels/map/lib/jquery.jvectormap.min.js b/src/app/panels/map/lib/jquery.jvectormap.min.js old mode 100755 new mode 100644 diff --git a/src/app/panels/map/lib/map.china.js b/src/app/panels/map/lib/map.china.js new file mode 100644 index 000000000..d8d4d789f --- /dev/null +++ b/src/app/panels/map/lib/map.china.js @@ -0,0 +1 @@ +$.fn.vectorMap('addMap', 'china',{"insets": [{"width": 2000.0, "top": 0, "height": 800, "bbox": [{"y": -22671671.123330014, "x": -40004297.151525836}, {"y": 8930392.02513512, "x": 40026572.394749384}], "left": 100}], "paths": {"103": {"path": "M413.032,414.183l-0.96,1.752c0,0,0.889,0.883,1.98,1.086s1.995-0.493,1.995-0.493L413.032,414.183zM413.032,414.183l-0.96,1.752c0,0,0.889,0.883,1.98,1.086s1.995-0.493,1.995-0.493L413.032,414.183z", "name": "Macao"},"21": {"path": "M329.934,230.111l0.24-5.476l1.785-2.499l-0.832-2.62l-9.168-3.454l0.594-3.691l2.858-4.049l-1.786-6.19l-0.835-0.952l-5.954,4.049l-2.855,9.168l-0.953,6.31l-4.762,3.93l-2.859,1.189l-3.438,0.779c0,0,9.184,11.236,7.729,9.458c-1.455-1.78,1.664,7.146,1.664,7.146l-0.834,3.449l5.357,2.859v2.262l4.881,1.19h1.43v-4.048l3.691-0.597l0.951-4.763l-2.619-2.026l-2.023-2.021l0.832-9.163l2.023-1.073l3.453,1.43L329.934,230.111z", "name": "Ningxia"},"30": {"path": "M391.37,382.632l2.265-1.666v-3.45l1.188-1.072l2.859,0.235l4.879,2.264l0.834-1.667l-1.188-2.025l0.354-1.427l3.098-2.619l5.478,1.427l3.096-1.905l2.264,2.265l5.478-1.429l1.07,2.021l-1.666,2.264l-2.859,4.288v1.069l1.67,1.192l11.43-4.525l4.048,2.264l1.19-1.191l-1.19-2.499l0.28-1.663l7.459,1.663l1.431,1.072l2.022-0.24l3.094,3.929l3.451,7.502l-2.26,1.667l-2.023,3.689l-1.786,0.596l-1.664,3.455l-5.716,2.854l-2.266-1.188l-1.426,2.382v0.833h-1.787h-3.098l-2.857,2.023l-2.021-1.188l-2.5,1.663l-6.314,2.619l-5.121-4.05l-0.354,3.217l1.788,4.882l-4.646,1.904l-2.498,3.452l-4.887,1.191l-2.617,1.073h-5.119c0,0-0.869,2.545-3.453,3.452c-2.584,0.904-9.168,3.213-9.168,3.213l-4.522,3.098l-2.265,2.263l4.287,6.903l-2.856,2.501l-3.451-0.238l-4.053-7.381l0.954-5.238v-2.501l2.854-4.646l3.695-0.831l-0.355-2.501l3.809-1.785l0.476-4.288l6.668-5.119l-0.355-6.905l5.119-6.547l-0.24-2.5l1.666-2.381L391.37,382.632z", "name": "Guangdong"},"15": {"path": "M196.462,200.108l-1.43-16.55l0.836-3.453l4.879-2.262c0,0,5.209-5.03,6.903-5.717c1.696-0.686,10.6-4.285,10.6-4.285l4.285-2.025v-4.047l1.905-2.262l1.788,0.237l7.144,1.192l-0.358,3.095l1.43,4.88l-0.834,7.978l6.072,8.929l3.097,2.026l4.883-3.812h10.237l2.623,0.953l1.429,2.264l-1.193,2.499l-5.714,4.645l0.597,2.261l6.549,4.882h2.618l0.834,1.07l-0.596,2.025l4.05,3.217l9.404,1.429l4.525-1.19l5.718-5.719l6.903,0.598l2.855,4.287l-1.664,3.929l0.475,2.382l-3.688,2.263l-1.668,2.024l0.596,4.763l6.545,4.646l2.875-0.653l7.725,9.458l1.668,7.145l-0.834,3.451l5.357,2.859v2.26l4.883,1.192h1.426v-4.05l3.693-0.595l0.951-4.763l-2.619-2.026l-2.025-2.021l0.834-9.166l2.023-1.071l3.453,1.43l1.432-0.598l0.834,1.667l9.166,4.639l4.883,3.1l0.832,2.856l-2.619,3.691l1.431,4.285l-0.834,2.021l-6.785,0.6l-1.433,0.833l0.478,1.191v1.903l-5.355,0.594l-2.856-1.428h-3.691l-0.596,0.834l0.596,2.024l-1.789,2.023l-0.592,2.262l3.449,2.857l-2.498,5.119l1.072,2.622l-0.238,1.188h-4.051l-2.854,1.435l2.26,3.091l-1.428,4.051l-4.287,1.07l0.357,2.023l-1.189,1.428l-7.383-0.596l-2.854-2.021l-0.601-4.525l-1.664-1.669l-2.62,1.669l-4.523-4.521l-3.455-2.385l-0.354-3.335l-1.074-2.619h-1.787l-7.144,3.096l0.356,3.454h-2.618l-4.287-4.288l-4.525-0.593l-1.786-2.499l1.431-2.86l2.617,2.5l3.097,0.954l2.62-2.025v-4.881l2.857-2.62l2.265-2.263l-1.073-2.856l5.716-4.522l0.832-7.147l-2.619-3.688l-1.429-6.071l-7.144-9.405l-3.692,1.431l-5.118-4.524l-6.907-4.287l-2.856-6.905l-5.359,2.023l-9.999-6.309l-4.883,2.616l-7.501-1.188l-5.714,3.452l-3.691,0.237l-5.715-3.451l-3.93-2.265L196.462,200.108z", "name": "Gansu"},"16": {"path": "M305.646,387.87l3.688,0.241l4.051-3.694l1.668,1.072l7.737,3.216l1.429-0.835l0.235-2.619l1.433-1.429l10.955-7.145l1.903,2.266l6.668,2.021l3.691-4.883l1.666,1.192h2.619v-1.431l3.453-1.192v-1.069l1.43-1.428l0.832,0.236l3.453-3.451l2.856,0.832l2.857-3.931l1.432,3.099l0.832-0.238l4.525-4.288l1.188,0.24l2.021-1.073l3.693,1.073v4.048l2.856,0.595l-0.832,3.929l-2.623,4.29l-1.188,3.688h1.188l3.101-2.854l2.616,5.713l2.025-1.43h2.26l1.666,5.717l-1.666,2.383l0.24,2.5l-5.119,6.547l0.355,6.905l-6.668,5.12l-0.476,4.285l-3.809,1.787l0.354,2.5l-3.694,0.831l-2.853,4.646l-7.502,1.071l-3.93-2.856l-4.049-1.669l-4.049,4.05l-4.158,0.241l-4.058,0.234c0,0-10.996-6.139-9.168-5.119c1.828,1.021-1.666-4.526-1.666-4.526l2.261-4.646l-2.617-1.902h-3.455l-0.832-0.952l-3.691,0.952l-3.692-2.62l1.432-4.048l2.855-0.235l1.069-0.834l0.957-3.69l-1.192-2.024l-9.765-1.785l-1.668-2.856h-2.854h-2.619l-1.906-3.099L305.646,387.87z", "name": "Guangxi"},"01": {"path": "M423.637,253.208l2.024-0.597l6.312,2.621c0,0,1.768,2.299,2.861,2.856c1.092,0.557,5.118,1.43,5.118,1.43l2.021,1.667l2.858-0.479l0.599,1.072l-0.957,6.074l2.858,1.666l1.189,2.263l4.287,0.831l1.666-2.854l2.621,0.356l1.666,2.265l-0.24,2.021l-5.121,0.596v2.264v1.665l-2.021,2.265l1.43,2.618l4.287,2.856l0.237,3.454l8.572,0.832v4.525l-1.666,2.381l1.191,2.263l-0.951,1.43l-3.338,0.594l-1.428,1.906l0.235,4.882l-4.285,6.072l-0.715,0.683l-2.381-2.111H446.5l-2.498-2.855l-4.884,4.761l-1.786-0.834l2.026-3.69l-0.24-1.188l-1.786-0.479l-5.718,3.099l-5.356-10.241l1.666-3.214l-0.595-1.071l-2.858-0.952l-4.76-2.858l1.903-3.928l2.855-1.43l0.598-3.214l-1.07-5.716l-0.596-0.479l-2.856,2.86c0,0-5.978-4.647-4.287-3.453c1.69,1.192-3.217-4.049-3.217-4.049l3.217-2.261l0.834-4.05l2.021-1.431l-0.354-5.359l1.43-1.188l2.619,1.787l1.664,2.26l3.453-2.26l1.192-1.434l-0.598-2.617l-4.049-2.263L423.637,253.208z", "name": "Anhui"},"102": {"path": "M417.745,409.005l3.394,0.773l3.453-2.558l1.666,4.582c0,0-5.521,2.673-3.691,1.785c1.828-0.884-4.641-0.355-4.641-0.355l-0.834-3.454L417.745,409.005z", "name": "Hong Kong"},"07": {"path": "M435.945,374.779c0,0,2.881-12.508,1.742-10.365c-1.137,2.144,1.672-2.62,1.672-2.62l0.83-2.854l2.023-4.286l-1.072-1.668l0.24-3.691l4.881-5.475l-0.357-3.691l3.215-5.478l3.095,0.834l6.311-4.524l1.193-2.26l3.69,0.593l2.025,5.118l1.666,3.454h4.047l2.498-3.215l3.693,3.69l6.454-2.276l-4.069,9.776l-2.385-1.192l-1.666,0.835l-0.238,0.954l2.262,2.501l-0.598,8.929l0.598,2.859l-0.598,0.834l-2.617-0.599l-1.668,1.667l1.191,2.384l-3.214,3.095l0.595,1.189l-3.097,1.665l0.478,2.264l-1.072,1.191h-4.285l-2.264,2.025l-0.357,0.832l2.023,1.428l-2.26,3.452l-2.859,3.691l-1.189-0.356l-3.1,3.216l-3.447-7.502l-3.098-3.929l-2.023,0.24l-1.43-1.072L435.945,374.779z", "name": "Fujian"},"22": {"path": "M421.139,189.75l-0.357-2.856l-0.832-1.905l5.095-2.126l0.381-1.683l-1.189-4.767h-1.668l-6.666-3.449l-3.69,3.69c0,0-1.125,6.585-0.832,4.88c0.289-1.704-3.693,4.288-3.693,4.288l-0.594,4.286l0.832,2.263l4.881-0.834l3.693,1.071l1.784-1.667L421.139,189.75z", "name": "Beijing"},"09": {"path": "M371.131,276.068l9.405,8.336l7.742,1.665l7.144-1.072l2.262,1.072l2.5-1.43l1.783,1.787l0.834,2.856l3.455,1.905h4.524l3.451,2.857l3.098-1.428l2.382,1.428l1.903-3.929l2.855-1.43l0.598-3.216l-1.07-5.715l-0.596-0.479l-2.856,2.86l-4.287-3.453l-3.218-4.049l3.218-2.263l0.834-4.048l2.021-1.431l-0.354-5.359l1.43-1.188l2.619,1.787l1.664,2.26l3.455-2.26l1.19-1.434l-0.598-2.617l-4.049-2.263l-0.834-2.619l-7.142,0.835l-4.524-3.93l-2.021-0.596v-2.621l10-11.074l-3.69,0.834l-2.261,1.669l-0.957-1.429v-1.666l-1.663-0.6l-4.525,1.785l-11.43-1.428l-0.597,9.408c0,0-6.604,5.169-5.479,4.287c1.129-0.884-7.381,1.429-7.381,1.429l-10.359,7.142l-8.215,2.264v1.43l7.738,11.666L371.131,276.068L371.131,276.068z", "name": "Henan"},"29": {"path": "M313.622,349.296l-0.836-2.858l-2.618-0.954l-4.283,2.622l-2.859-1.432l-0.238-3.688l-1.43-1.79v-1.903l-4.049-0.952l-1.07,1.188l0.599,2.859l-3.217,1.43l-0.834,2.021l0.834,2.5l-7.146,8.336l1.191,9.766l-3.453,2.854l-1.666-1.784l-6.907,4.048l-2.618-1.431c0,0-11.535-22.106-10.002-19.172c1.533,2.938-3.931-2.854-3.931-2.854l-3.213-0.834l-1.432-2.619l1.787-2.859l-2.857-2.263l-3.455,2.859l-3.451,0.598l-2.263-10.363l-0.596-2.499l-3.454,4.286l-1.427,0.831l0.356,6.551l-0.834,1.431h-1.784l-1.43-1.431l-1.667,2.026l1.667,7.381h2.024l1.667,1.19c0,0,0.468,2.396,0.594,4.521c0.125,2.125-0.833,15.719-0.833,15.719l-10.837,9.766l-0.594,3.689l-2.024,1.787l-0.238,1.903l1.669,4.643l-1.431,3.454l0.834,0.478l5.478-1.433l7.738-0.476l-0.834,3.098l1.431,2.857l0.475,4.287l0.955,1.426l4.524,0.243l2.024,1.425l-2.264,2.856l-0.356,3.453l-1.667,4.05l1.068,1.43l2.86,0.238l4.881,1.784l-0.593,1.667l3.212,4.881h4.524l5.716-3.213l1.786,0.952v1.906l0.832,2.856l1.432,1.429l3.092-0.477l1.192,0.834l1.072-1.192v-4.525l-1.906-8.333l1.431-2.5h4.762h1.192l2.62-3.213l6.783,2.261l2.858-2.503l1.431,1.432l2.858-1.786l2.615,2.618h1.073l0.953-1.428l2.261-2.263l1.073,0.833l3.213-0.595l3.099-2.502l2.619-3.811l3.688-0.831l2.023,2.021l1.43-4.048l2.857-0.235l1.069-0.834l0.957-3.691l-1.192-2.023l-9.765-1.785l-1.668-2.857h-2.854h-2.619l-1.906-3.097l0.24-1.665l1.188-6.907l-3.809-3.689l2.859-12.027l-1.908-1.667l-6.309,1.906l-1.431-2.501v-2.856l-1.428-1.43l3.094-4.286l3.453,1.07l1.43-1.429l6.313,0.951l2.856-0.951L313.622,349.296z", "name": "Yunnan"},"13": {"path": "M153.889,69.508l2.327-0.014l-1.428,4.525l2.025,2.38l0.236,1.666l4.525,4.524l1.191,3.453l5.953,0.357l2.62,2.265h1.429l3.453,7.379l3.451,8.931l-1.784,5.357l0.358,2.025l-3.215,5.477l0.833,4.286l11.192,4.763l12.025,1.788l12.503,8.571l4.049,1.429l0.237,2.261l2.619,5.478l2.619,7.146l3.333,5.953l-1.903,2.263v4.047l-4.286,2.026l-10.596,4.284l-6.907,5.719l-4.881,2.26l-0.834,3.453l1.43,16.55l-3.931-0.596l-1.783,1.431l-26.315,5.119l-3.691,2.856l0.358,6.906l7.978,6.548l-2.62,4.286l-3.69,1.668l-0.597,2.024l0.835,2.259h2.021l1.192,1.429l-7.738,2.617l-4.525-1.667l-2.382-1.424h-5.715l-10.24-4.642h-6.546l-5.121,1.428h-5.714l-8.931,4.879l-7.143-0.834l-7.145,2.5l-5.956-1.907l-3.689-3.211l-9.525-1.427l-6.191,4.28l-3.452-1.425l-2.858-2.263l-6.907-1.667l-1.07-1.189l-2.857-0.237l-9.782,5.945l-10.037-1.25l-0.822-0.359l1.113-8.623l-4.524-1.191l-9.406-6.902l-2.62-0.241l-2.023-4.525l1.427-4.643l-0.477-2.26l-3.451-2.266l-1.192-2.26l-7.143-4.049v-1.189l3.452-1.431l2.023,1.19l2.025-2.025l-0.598-6.785l0.598-5.716l-4.646-4.642l-3.095,0.833l-1.189-3.336l1.785-3.452l-0.952-3.214l3.038-2.749l1.248-1.182v-2.618l4.285-2.024l4.286-0.833l3.811-1.429l3.099,0.832l2.26-0.832l0.833,0.595l0.356,2.859l2.022,0.832l4.765-0.238c0,0,3.566-4.729,5.478-6.073c1.911-1.346,11.19,2.381,11.19,2.381l5.717-4.048l16.552-3.689l1.069-2.264l1.43-6.31l4.643-3.69h1.433v-1.906l0.236-15.836l0.833-3.212l-4.521-1.668l-0.24-1.191l4.762-1.428l12.384-1.073l1.905,2.501l4.287,0.952l1.192,0.239l1.665-2.262l-2.265-2.263l9.169-18.574l1.431-0.953l8.335,4.047h3.689l1.667,2.264l7.979-2.502l2.023-13.212l3.452-2.265l4.048-0.238l2.859-3.452l1.071-3.454l2.263-1.191L153.889,69.508z", "name": "Xinjiang"},"26": {"path": "M363.393,259.519l-1.428-3.454l2.498-8.81l-3.689-16.903c0,0,3.262-5.777,2.619-4.286c-0.646,1.49,1.07-3.929,1.07-3.929l-3.334-6.905l3.096-4.884l0.594-4.525l1.67-3.452l-0.238-4.046l-1.432-1.074l-2.26,2.502l-6.072,0.356l-3.096,4.526l0.236,2.62l-0.593,1.665l-2.502,0.834l-9.406,13.454l-1.19-0.836l-2.617-0.594l-5.359,0.359l-1.789,2.499l-0.233,5.478l0.834,1.667l9.166,4.637l4.883,3.099l0.832,2.855l-2.619,3.691l1.431,4.286l-0.835,2.021l-6.784,0.6l-1.433,0.835l0.478,1.188v1.904l-5.355,0.596l-2.856-1.428h-3.691l-0.596,0.832l0.596,2.026l-1.789,2.022l-0.592,2.261l3.451,2.861l-2.5,5.117l1.071,2.619l-0.237,1.191h-4.052l-2.854,1.429l2.262,3.098l-1.43,4.048l2.383,0.478l0.238,2.617l2.021,0.237l7.386-1.427l1.43,0.593l0.354,2.025l3.099,0.835l6.547,3.216l3.69-1.434l8.097,2.857l1.666,2.26l4.051-0.829l-0.596-4.288l-0.834-1.191l0.834-3.451l4.286-2.021l1.068-1.668l-2.26-0.837l-2.5-0.593l-2.619-2.62l1.189-1.068h8.571h1.908l1.189,0.83l2.616-2.022v-3.454l-7.737-11.668L363.393,259.519L363.393,259.519z", "name": "Shaanxi"},"19": {"path": "M491.15,173.2l6.783-10.002l4.287-4.881l-0.595-4.763l-4.524-5.239l-0.594-4.286l-8.216-11.075l-0.358,1.074l-1.666,1.786l-3.453-4.05l-4.883-1.429l-0.236,1.429v2.264l-2.022,2.022l-4.047,4.05H467.1l-1.666,2.856h-1.789l-3.094,3.096h-1.787l-3.691,3.691l-2.262,0.596l-4.881,7.5l-3.096-4.644l-3.453-2.262l-1.666,1.667l1.903,10.002l-1.666,3.453l-1.668,5.12l4.763,3.215l2.621,0.238l3.45,4.881l2.5-1.429c0,0,2.857-2.881,4.05-4.882c1.192-2.002,4.049-6.788,4.049-6.788l6.787-1.429l4.287,4.286l-3.099,6.787l-4.049,6.311l3.688,2.62l-0.233,3.098l-2.857,2.855l0.597,1.19l4.881-2.619l7.143-9.407l10.836-6.072L491.15,173.2z", "name": "Liaoning"},"32": {"path": "M279.33,280.95l1.788-4.05l-2.025-2.261l-0.357-3.454l7.145-3.096h1.787l1.069,2.619l0.357,3.336l3.455,2.384l4.522,4.521l2.621-1.669l1.664,1.669l0.6,4.525l2.855,2.021l7.383,0.599l1.189-1.431l-0.357-2.023l4.287-1.07l2.381,0.478l0.238,2.617l2.024,0.237l7.382-1.427l1.43,0.593l0.354,2.026l3.099,0.834l6.549,3.214v7.47l-3.932,1.059l-1.351,7.671l-5.346,3.72l-1.014,5.811l-4.564-2.092l-5.58,2.092l-0.231,4.416l-0.464,4.53l6.507,4.07l2.28,6.977l-2.623,0.833l-3.928-2.263l-3.213,3.691v1.666l6.311,3.452l1.427,2.62l-4.523,1.666l-6.904-0.238l-0.831-2.855l-2.621-0.954l-4.285,2.623l-2.859-1.429l-0.238-3.694l-1.43-1.786v-1.903l-4.047-0.952l-1.072,1.188l0.599,2.858l-3.215,1.431l-0.836,2.021l0.836,2.504l-7.146,8.334l1.191,9.764l-3.453,2.855l-1.666-1.784l-6.906,4.049l-2.621-1.431l-10.001-19.17l-3.931-2.854l-3.216-0.835l-1.428-2.623l1.787-2.854l-2.857-2.264l-3.455,2.858l-3.45,0.595l-2.264-10.359l-0.597-2.499c0,0-2.04-22.568-0.594-16.55c1.446,6.017-3.099-8.336-3.099-8.336l2.267-1.665l-6.55-12.027l-7.977-6.311l1.069-3.692l0.953-1.188l11.669-1.666l7.738,2.262l4.523-1.431l1.785,2.859l5.717,5.715l4.524-0.833v-3.453l1.191-2.266l4.522-1.783l1.667,2.856l2.621-1.903l3.689,0.478v-0.241H279.33z", "name": "Sichuan"},"05": {"path": "M544.896,113.042l-2.07-0.088h-2.858l-4.285-1.431l-1.43-2.619l-1.431,2.024l-2.022-1.428l-4.523,5.12l-0.834,1.427l-2.022,0.357l-2.859-3.214l-2.621-1.072l-2.854-5.715l-2.027,1.431l0.594,5.12l-1.426,0.833l-3.689-4.05l-1.432-1.903h-2.854l-1.666-4.288l-3.813-2.023l-5.354,2.023l-2.025-0.357l-3.098-3.094l-4.285,2.5h-2.383l-2.857,1.191l-4.285-3.096l-2.854-5.24l-6.787,1.189l-2.621,3.099l-0.238,3.45l-7.502-2.023l-1.074,2.381l0.601,1.667l3.928,2.859v4.046l0.594,3.929l2.265,3.456l0.356,3.095l1.666,1.191l5.717-5.479l5.953,7.502v4.288l3.213,1.667l0.238-1.431l4.885,1.431l3.451,4.046l1.666-1.784l0.357-1.074l8.217,11.075l0.594,4.286l4.527,5.239l0.592,4.761l4.051-2.499l3.689-10.598l1.67-0.595l4.047,2.263l6.549-0.834l2.26-2.024l-3.092-4.763l0.832-1.191c0,0,7.84-2.611,6.072-2.022c-1.766,0.588,2.5-4.883,2.5-4.883l3.215-1.428l0.238-4.766l0.832-3.212l1.785-0.596l1.668,1.789l1.668,1.426l4.287-5.715l1.188-4.288L544.896,113.042z", "name": "Jilin"},"04": {"path": "M483.646,282.616l-1.426,4.286l-1.898,2.251l-3.225,3.824l-4.879-0.835l-3.929-2.383l-2.383,1.19l-8.571-0.832l-0.238-3.454l-4.287-2.856l-1.428-2.618l2.02-2.264v-1.665v-2.267l5.121-0.594l0.24-2.023l-1.666-2.263l-2.621-0.355l-1.666,2.854l-4.287-0.831l-1.188-2.263l-2.857-1.666l0.955-6.074l-0.598-1.072l-2.859,0.479l-2.021-1.667l-5.118-1.429l-2.861-2.857l-6.307-2.621l0.592-2.856l2.5-1.069l4.645,3.927h1.433l4.284-0.476l2.5-2.022l3.453,2.856l1.427-2.62l0.358-1.43l2.857-1.667l0.834-3.45l2.854-0.597l7.148,4.881c0,0,3.365,0.754,5.117,2.025c1.754,1.271,9.766,16.313,9.766,16.313l-0.357,1.666l6.548,3.095l1.784,2.859l3.099,1.429l1.428,2.855l-2.023,0.951l-3.334-1.188h-4.645l-4.287-1.432l-1.666,1.432l3.932,1.188l3.813,1.669L483.646,282.616z", "name": "Jiangsu"},"06": {"path": "M153.954,234.989l4.523,1.667l7.742-2.617l-1.193-1.429h-2.021l-0.834-2.259l0.594-2.024l3.692-1.668l2.617-4.286l-7.977-6.548l-0.356-6.906c0,0,2.08-2.545,3.689-2.856c1.609-0.313,26.317-5.119,26.317-5.119l1.783-1.428l3.931,0.594l13.215,3.095l3.93,2.265l5.714,3.451l3.692-0.237l5.714-3.452l7.501,1.188l4.882-2.616l9.999,6.309l5.36-2.023l2.856,6.903l6.907,4.286l5.119,4.527l3.691-1.431l7.146,9.405l1.426,6.071l2.619,3.688l-0.832,7.146l-5.715,4.524l1.073,2.856l-2.265,2.263l-2.856,2.62v4.879l-2.621,2.027l-3.097-0.954l-2.617-2.5l-1.431,2.859l1.787,2.499l4.524,0.594l4.287,4.288h2.618l2.024,2.265l-1.787,4.046v0.239l-3.688-0.479l-2.621,1.905l-1.666-2.856l-4.524,1.785l-1.19,2.264v3.451l-4.524,0.836l-5.715-5.716l-1.787-2.856l-4.524,1.428l-7.738-2.262l-11.67,1.666l-0.952,1.189l-1.071,3.69l-2.263,1.43l0.238,3.692l-6.906,8.931l-11.43-2.383l-0.833-4.285l-7.146-5.718l-15.717-2.498l-6.786-1.19l-2.621-0.238l-5.953-4.883l-12.384-2.857l-8.57-16.551l-0.238-4.642l3.451-1.672v-5.117l2.502-6.313l-2.858-2.856L153.954,234.989z", "name": "Qinghai"},"31": {"path": "M385.895,447.523l-5.119,8.93v3.929l-10.238,8.336l-10.598-3.689l-2.025-7.501l0.597-3.454c0,0,8.074-8.075,5.715-5.716c-2.357,2.358,2.025-1.665,2.025-1.665l9.403-1.668l4.289-0.358l1.426-1.666l3.103,0.832L385.895,447.523z", "name": "Hainan"},"23": {"path": "M484.32,292.485l-3.998-3.332c0,0,0.867-0.375,1.898-2.251c1.031-1.875,1.426-4.286,1.426-4.286l4.287,1.788l2.027,2.854l-1.433,2.024L484.32,292.485z", "name": "Shanghai"},"10": {"path": "M413.04,235.229l0.357-1.426l-1.783-3.453l6.902-12.5c0,0,8.725-7.9,6.313-5.718c-2.411,2.185,4.523-1.188,4.523-1.188l4.268-5.423l-1.647-1.125l-1.56-3.907l-3.319,1.286l-5.479-1.428l-0.237-1.428l-0.238-9.17l3.69-1.667l-0.419-1.563l-0.177-0.104l0.81-3.557l-5.094,2.128l0.832,1.905l0.178,1.424l0.18,1.433l-2.857,1.19l-1.785,1.667l-3.692-1.071l-4.881,0.834l-0.832-2.264l0.594-4.287l3.693-4.286l0.831-4.88l3.691-3.691l6.666,3.454h1.668l1.189,4.762l1.905,0.95l0.953,3.1l-0.356,2.024l4.047,2.854l0.594,2.264l3.338,1.428l8.332-4.523v-2.621l4.883-7.143l-3.45-4.881l-2.621-0.238l-4.763-3.218l1.668-5.118l-7.387-0.595l-3.213-4.765l0.357-2.619l-6.31-6.906l-4.051,2.026l-3.451,3.452l1.191,2.62l-0.834,1.667l-4.882,0.237l-2.264,2.022l-2.022-0.835l-2.021,2.026l-4.527,3.453l-2.024-1.43v-4.644l-1.666-0.832l-2.619,1.189l-3.096,6.547l-1.189,6.311l3.689,6.19l3.215,2.858v5.24l1.904,4.286l-0.834,4.764l-4.884,3.213l-2.26,7.382l4.049,4.645l2.857,5.717l-1.785,2.857l-0.477,3.928l-1.787,2.619l-0.834,2.859l2.621,3.446l11.43,1.431l4.524-1.787L413.04,235.229z", "name": "Hebei"},"08": {"path": "M464.838,96.639l6.787-1.19l2.854,5.241l4.285,3.095l2.856-1.188h2.386l4.285-2.501l3.094,3.094l2.024,0.357l5.357-2.023l3.813,2.023l1.666,4.288h2.857l1.43,1.904l3.689,4.049l1.426-0.833l-0.594-5.12l2.026-1.432l2.854,5.716l2.621,1.074l2.858,3.212l2.021-0.357l0.836-1.427l4.523-5.12l2.022,1.428l1.43-2.022l1.431,2.619l4.283,1.429h2.86l2.07,0.088l-1.238-2.113l-0.598-6.906l-5.115-7.978l2.855-2.857l2.616-4.883h9.646l1.785-1.665l-0.597-3.69l2.025-3.691l-0.596-2.024l0.832-3.451l-0.236-17.742l2.855-5.715l-3.214-3.692l0.595-2.261l-1.427-2.024l-3.69,1.429l-4.289,4.884l-4.283,2.023l-4.289,5.951l-10.598,3.692l-4.879-3.692l0.594-2.262l-2.5-3.689l-1.191-3.811l-4.047-0.239l-7.145-3.69l-2.859,1.071l-3.33-1.667l-4.887,0.834l-4.283-1.429l-2.621-3.69l-2.498-2.857l-0.951-2.857l-3.334-3.452l-2.026-3.099l-4.644-6.31l-1.428-3.69l-5.119-6.548l-1.432-3.454l-6.549-3.216l-4.287,1.429l-3.689-0.833l-8.336-1.668l-11.07,3.932l-2.024,1.786l2.262,3.096l-2.856,7.499l0.834,0.835l4.881,3.096l2.621-4.286l4.524,2.856l-0.235,2.022l1.664,5.119l2.854,3.218l5.717,0.833l1.668-1.787l3.451-0.477l6.547-5.476l8.576,6.31l-2.858,11.669l0.594,8.333v5.119l-2.26,1.191l-0.238,13.335l-0.597-0.476l-2.26-2.858h-1.192l-0.595,1.073c0,0-8.797,13.044-7.146,10.596c1.652-2.448-3.451,4.523-3.451,4.523l0.357,1.428l7.145,4.886l3.926-1.071l0.599,1.071l-0.834,1.189l-3.689,1.667l-0.359,3.214L464.838,96.639z", "name": "Heilongjiang"},"24": {"path": "M363.393,259.519l8.217-2.265l10.357-7.142l7.381-1.431l5.477-4.287l0.599-9.405l-2.623-3.449l0.836-2.856l1.787-2.619l0.477-3.929l1.785-2.86l-2.859-5.713l-4.047-4.645l2.262-7.383l4.886-3.212l0.83-4.765l-1.904-4.286v-5.242l-3.215-2.854l-7.381,3.809l-1.191-1.189l-3.93,2.855l-3.213-0.235l-6.312,9.048h-1.906l-3.452,2.858l0.237,4.046l-1.67,3.452l-0.594,4.525l-3.096,4.884l3.334,6.905l-1.07,3.929l-2.619,4.286c0,0,4.146,18.996,3.689,16.903s-2.498,8.81-2.498,8.81L363.393,259.519z", "name": "Shanxi"},"14": {"path": "M152.525,339.529l6.787,0.834l2.265,3.216l1.189,0.477l10.239-1.904l0.594-1.787l2.023-1.07l4.884-4.05l4.285-0.594l3.93-2.501l7.74-4.286l0.832,1.428l5.716,1.904l8.334-4.285l2.618,1.787l-2.379,3.452l0.952,0.833h3.332l0.359,1.427l-2.857,5.121l0.833,0.834h1.666l8.336,2.265l3.691-3.099l5.478,4.289l1.667-2.026l1.43,1.431h1.784l0.834-1.431l-0.356-6.549l1.429-0.835l3.451-4.284l-0.594-16.549l-3.099-8.337l2.265-1.665l-6.548-12.027l-7.979-6.311l-2.26,1.43l0.238,3.692l-6.908,8.931l-11.428-2.384l-0.833-4.286l-7.146-5.716l-15.717-2.498l-6.787-1.188l-2.619-0.241l-5.952-4.883l-12.385-2.857l-8.57-16.551l-0.238-4.642l3.451-1.672v-5.117l2.502-6.311l-2.858-2.858l3.811-3.095l-2.383-1.425h-5.716l-10.238-4.644h-6.549l-5.118,1.43h-5.715l-8.931,4.879l-7.144-0.834l-7.146,2.5l-5.954-1.906l-3.688-3.212l-9.526-1.427l-6.192,4.28l-3.45-1.425l-2.859-2.263l-6.908-1.667l-1.065-1.189l-2.857-0.237l-9.782,5.945l-10.412-1.297l2.428,4.398l2.68,1.995l-0.821,3.842l-0.231,3.758l0.256,2.672l0,0l-0.193,3.208l3.451,3.454l0.239,4.884l-1.072,1.907l-5.119,0.591l-2.621-2.854l-2.619,0.355l-0.476,2.265l1.428,3.688l0.479,2.62v3.333l-0.833,2.381l0.354,1.909l3.336,0.356l1.785,3.094l7.739,6.071v1.906l5.716,6.311l1.902,2.262l1.79,0.595l3.451-3.451l3.096,2.856c0,0,15.395,13.684,13.098,11.193c-2.297-2.491,2.381,5.715,2.381,5.715h2.859l1.667-1.665l1.426,1.428v5.117l7.741,4.287l1.667-0.357l1.191,4.287l6.548,3.81l0.238,2.501l1.188,0.835l5.717-0.24h3.098l4.644,3.457l10.24-0.359l5.476-0.239l1.428,2.265l-1.188,4.883l1.427,1.664l5.715-4.761l7.146-5.239l5.12,0.95L152.525,339.529z", "name": "Xizang"},"28": {"path": "M430.413,200.491c0,0-1.832,1.672-3.319,1.284c-1.49-0.388-5.479-1.428-5.479-1.428l-0.237-1.429l-0.238-9.169l3.69-1.667l-0.596-1.666l0.81-3.557l0.385-1.683l1.901,0.95l0.953,3.098l-0.356,2.022l4.047,2.858l0.594,2.263l-2.379,1.668l-0.834,3.809L430.413,200.491z", "name": "Tianjin"},"18": {"path": "M313.622,349.296l-1.666,4.761l-2.856,0.951l-6.313-0.951l-1.43,1.429l-3.453-1.07l-3.094,4.286l1.428,1.43v2.856l1.431,2.501l6.309-1.906l1.908,1.667l-2.859,12.027l3.81,3.689l-1.188,6.907l3.688,0.238l4.051-3.695l1.668,1.073l7.737,3.216l1.429-0.832l0.235-2.622l1.433-1.429l10.955-7.144l1.903,2.265l6.668,2.021l3.689-4.883l1.668,1.192h2.619v-1.432l3.453-1.189v-1.071l1.43-1.428l0.832,0.237l3.453-3.452l-2.857-5.123l1.429-7.142l-1.785-2.263l-5.121,1.428l-0.596-0.834l5.717-6.309l-2.5-10.001l-3.81,2.855l-3.334-3.45l-3.215-4.29l-0.24-2.619l-2.26-0.477l-2.621,0.834l-4.287-2.024l-2.022,4.883l-3.691,0.239l-2.619,4.049l-1.666-0.834l-2.623,0.834l-3.928-2.266l-3.213,3.69v1.668l6.312,3.453l1.426,2.621c0,0-6.094,2.245-4.523,1.667C322.1,348.955,313.622,349.296,313.622,349.296z", "name": "Guizhou"},"101": {"path": "M505.438,371.203l-3.217,19.169l-1.664,6.07v5.123l-1.43,1.427l-3.451-5.119l-3.693-2.858l-3.215-8.571c0,0-0.451-5.62,0.357-7.74c0.809-2.118,5.356-14.05,5.356-14.05l6.313-5.357l4.051,1.904L505.438,371.203z", "name": "Taiwan"},"12": {"path": "M356.486,329.29l1.787-4.048l5.119-4.287l4.881,2.026l3.096-2.026l-2.621-3.093l1.429-1.433l13.219,0.836l4.525,3.097l2.264,1.425l3.451-2.26l2.619-0.833l0.596,3.093h1.904l1.43-2.021l2.856-2.86l1.431,2.027v4.049l1.19,1.667l2.619,0.594l2.855-2.854l4.287-1.433l7.979-7.381l3.691,0.236l4.522-1.428l-5.358-10.24l1.668-3.214l-0.593-1.071l-2.862-0.952l-4.761-2.858l-2.381-1.427l-3.098,1.427l-3.451-2.854h-4.524l-3.455-1.907l-0.83-2.856l-1.787-1.786l-2.5,1.428L395.421,285c0,0-9.509,0.927-7.146,1.071c2.363,0.146-7.736-1.666-7.736-1.666l-9.407-8.334l-2.619,2.023l-1.188-0.831h-1.907h-8.572l-1.189,1.068l2.619,2.62l2.5,0.593l2.26,0.837l-1.067,1.668l-4.287,2.021l-0.834,3.451l0.834,1.191l0.596,4.288l2.5,0.238l2.619,3.452l1.07,6.548l-0.832,2.262l-1.666-0.594l-4.883,3.812l-8.336,1.429l-2.261,2.263l1.783,2.262l0.24,4.882l2.262,0.598L356.486,329.29z", "name": "Hubei"},"25": {"path": "M425.661,252.611l0.597-2.856l2.5-1.069l4.645,3.927h1.433l4.284-0.476l2.5-2.022l3.453,2.856l1.429-2.62l0.356-1.43l2.857-1.667l0.834-3.45l2.854-0.595l7.98-13.454l-1.429-2.264l1.429-1.427l1.666,0.595l2.619-1.429l1.432-3.094l6.545-6.073l5.121-1.666l2.381-2.266l-0.592-4.88l-3.457-0.355l-7.738,0.952l-5.356-2.62l-3.216,0.596l-7.977,10.239l-2.262,1.429l-5.117-2.263l-0.359-2.619l-1.069-4.523l-2.859-1.669l-4.643,1.073l-2.882-1.971l-4.266,5.423l-4.523,1.188c0,0-8.514,7.798-6.313,5.718c2.201-2.081-6.902,12.5-6.902,12.5l1.783,3.45l-0.357,1.431v1.666l0.957,1.429l2.261-1.669l3.69-0.834l-10.002,11.074v2.621l2.023,0.596l4.524,3.93l7.146-0.835L425.661,252.611z", "name": "Shandong"},"33": {"path": "M318.986,317.871l5.58-2.092l4.564,2.092l1.014-5.811l5.346-3.72l1.351-7.671l3.932-1.059v-7.47l3.689-1.432l8.096,2.857l1.666,2.26l4.051-0.829l2.5,0.238l2.619,3.452l1.07,6.548l-0.832,2.262l-1.666-0.594c0,0-3.072,3.501-4.884,3.812c-1.809,0.311-8.336,1.429-8.336,1.429l-2.26,2.263l1.783,2.262l0.24,4.883l2.262,0.597l5.715,7.142l0.357,9.407l-3.218,2.412l-0.592,0.445l-3.334-3.451l-3.215-4.29l-0.24-2.619l-2.26-0.476l-2.621,0.834l-4.287-2.025l-2.022,4.883l-3.691,0.239l-2.619,4.049l-1.666-0.834l-2.28-6.977l-6.507-4.07L318.986,317.871z", "name": "Chongqing"},"03": {"path": "M408.279,325.242l3.336,6.549l0.355,3.452l-1.785,3.454l-2.502,2.024l-0.594,6.188l0.832,0.955l1.43-0.596l0.834,0.596v3.927l1.785,4.647l2.026,0.831l0.234,6.789l-1.193,4.642l1.193,2.021l2.266,2.265l5.474-1.429l1.071,2.022l-1.665,2.263l-2.859,4.287v1.07l1.67,1.192l11.43-4.525l4.047,2.263l1.191-1.19l-1.191-2.499l0.281-1.663l1.742-10.365l1.67-2.62l0.832-2.854l2.025-4.286l-1.072-1.668l0.238-3.691l4.881-5.475l-0.355-3.691l3.213-5.478l3.095,0.834l6.311-4.524l1.193-2.263l-4.049-7.501l-2.619-3.69l1.901-1.818l-2.381-2.111H446.5l-2.5-2.855l-4.884,4.762l-1.784-0.835l2.024-3.69l-0.24-1.188l-1.784-0.479l-5.716,3.099l-4.524,1.429l-3.689-0.238c0,0-9.709,9.669-7.979,7.381c1.731-2.287-4.287,1.433-4.287,1.433L408.279,325.242z", "name": "Jiangxi"},"11": {"path": "M408.279,325.242l-2.619-0.594l-1.188-1.667v-4.05l-1.43-2.026l-2.857,2.86l-1.43,2.023h-1.904l-0.594-3.096l-2.621,0.833l-3.451,2.263l-2.264-1.428c0,0-2.666-2.521-4.525-3.097c-1.857-0.576-13.217-0.832-13.217-0.832l-1.43,1.429l2.62,3.093l-3.096,2.026l-4.883-2.026l-5.117,4.287l-1.787,4.05c0,0-0.19,6.479,0.357,9.405c0.551,2.926,2.5,10.002,2.5,10.002l-5.717,6.31l0.596,0.833l5.121-1.428l1.785,2.263l-1.429,7.144l2.857,5.121l2.856,0.832l2.857-3.931l1.43,3.099l0.834-0.238l4.523-4.288l1.191,0.24l2.021-1.073l3.693,1.073v4.048l2.856,0.595l-0.832,3.929l-2.623,4.29l-1.188,3.688h1.188l3.103-2.854l2.617,5.713l2.021-1.43h2.264l2.263-1.666v-3.45l1.188-1.072l2.859,0.235l4.879,2.264l0.834-1.667l-1.188-2.023l0.354-1.429l3.098-2.619l5.478,1.428l3.096-1.906l-1.193-2.021l1.193-4.642l-0.234-6.789l-2.026-0.831l-1.785-4.647v-3.927l-0.834-0.596l-1.43,0.596l-0.832-0.955l0.594-6.188l2.502-2.024l1.785-3.454l-0.355-3.452L408.279,325.242z", "name": "Hunan"},"02": {"path": "M483.793,336.063l-6.455,2.276l-3.693-3.69l-2.498,3.215h-4.049l-1.666-3.454l-2.023-5.118l-3.692-0.596l-4.047-7.501l-2.619-3.69l1.903-1.818l0.716-0.685c0,0,6.241-8.84,4.286-6.07c-1.954,2.769-0.239-4.882-0.239-4.882l1.43-1.906l3.336-0.594l0.951-1.43l-1.189-2.263l1.666-2.382v-4.524l2.384-1.189l3.928,2.382l4.879,0.835l3.225-3.824l3.998,3.332l-1.744,1.324l-2.021,3.096l-3.217,0.952l-1.074,0.833l3.098,1.666l5.715-2.499l9.406,3.929l0.953,7.979h-3.809l-0.24,2.382l2.024,3.332l-1.784,2.024l2.022,3.214l-3.096,3.69l-1.43-1.787l-4.644,11.788L483.793,336.063z", "name": "Zhejiang"},"20": {"path": "M301.969,226.604l3.438-0.779l2.859-1.188l4.762-3.932l0.953-6.31l2.855-9.168l5.954-4.048l0.835,0.951l1.786,6.19l-2.858,4.049l-0.594,3.691l9.168,3.453l0.832,2.621l5.358-0.359l2.617,0.596l1.191,0.834l9.405-13.454l2.502-0.835l0.593-1.664l-0.236-2.623l3.096-4.523l6.072-0.358l2.262-2.5l1.431,1.074l3.452-2.86h1.904l6.312-9.046l3.215,0.235l3.93-2.855l1.191,1.189l7.381-3.809l-3.689-6.193l1.189-6.311l3.096-6.549l2.619-1.188l1.666,0.832v4.644l2.025,1.43l4.526-3.453l2.021-2.026l2.022,0.835l2.265-2.025l4.881-0.234l0.834-1.667l-1.191-2.622l3.453-3.452l4.049-2.024l6.31,6.908l-0.355,2.618l3.213,4.763l7.385,0.595l1.666-3.453l-1.903-10.002l1.666-1.667l3.453,2.262l3.096,4.644l4.881-7.5l2.264-0.596l3.689-3.692h1.787l3.094-3.095h1.787l1.666-2.856h4.527l4.047-4.051l2.021-2.021v-2.264l-3.213-1.667v-4.286l-5.953-7.502l-5.717,5.478l-1.666-1.19l-0.357-3.096l-2.264-3.453l-0.594-3.931v-4.046l-3.928-2.858l-0.601-1.667l1.074-2.382l7.502,2.022l0.238-3.452l2.621-3.099l-1.789-1.666l0.358-3.214l3.689-1.667l0.834-1.19l-0.598-1.07l-3.927,1.07l-7.145-4.882l-0.357-1.43l3.453-4.524l7.146-10.597l0.594-1.072h1.193l2.26,2.858l0.596,0.479l0.238-13.336l2.26-1.191v-5.121l-0.594-8.333l2.858-11.668l-8.575-6.312l-6.548,5.478l-3.45,0.476l-1.668,1.786l-5.718-0.832l-2.854-3.215l-1.664-5.122l0.236-2.021l-4.525-2.858l-2.621,4.289l-4.881-3.096l-0.834-0.835l2.856-7.5L433.4,7.223h-2.024l-5.119,3.688l-4.285,6.311l1.668,1.071l3.211,0.359l2.504,6.548l-1.43,2.618l-2.502,3.689l-4.644,17.147l1.785,2.856l-1.428,2.498l-10.599,7.742l-5.713-1.071l-3.215-1.191l-0.479,1.667l-4.642,18.577l-2.264,2.378l1.191,3.335l2.854,2.382l4.764-2.623l7.74,0.598l2.26-3.692l4.052-0.951l7.737,2.856l9.408,9.765v2.023l-2.024,1.429l-10.836,0.599l-3.691,2.854l-2.857-0.355l-2.022,3.214l-5.121,1.07l-3.457,5.12l-0.592,3.81l-7.379,4.763l-4.646,0.598l-5.119,6.904l-4.883,2.859l-9.408-2.025l-3.092-1.431l-3.692,3.694l-1.785,6.548l5.119,7.501l-3.335,3.451l-4.643,2.859c0,0-8.422,10.638-6.787,8.571c1.637-2.064-6.619,3.36-8.93,3.93c-2.31,0.568-14.525,1.429-14.525,1.429l-2.264-0.237l-16.906,7.144l-7.742,4.881l-2.262-1.19l-0.83-2.262l-10.36-0.597l-11.909-3.688l-3.211-3.69l-17.385-2.025l-3.217,1.43l-21.072-2.022l-0.358,3.095l1.43,4.883l-0.834,7.976l6.073,8.929l3.096,2.026l4.883-3.812h10.237l2.623,0.953l1.426,2.262l-1.19,2.5l-5.714,4.646l0.597,2.261l6.549,4.88h2.618l0.834,1.072l-0.596,2.023l4.05,3.217l9.403,1.429l4.527-1.19l5.716-5.719l6.903,0.598l2.857,4.289l-1.664,3.926l0.473,2.382l-3.688,2.263l-1.668,2.024l0.596,4.76l6.545,4.647L301.969,226.604z", "name": "Neimenggu"}}, "height": 470, "projection": {"type": "mill", "centralMeridian": 11.5}, "width": 600.0}); diff --git a/src/app/panels/map/lib/map.europe.js b/src/app/panels/map/lib/map.europe.js old mode 100755 new mode 100644 diff --git a/src/app/panels/map/lib/map.usa.js b/src/app/panels/map/lib/map.usa.js old mode 100755 new mode 100644 diff --git a/src/app/panels/map/lib/map.world.codes.js b/src/app/panels/map/lib/map.world.codes.js old mode 100755 new mode 100644 diff --git a/src/app/panels/map/lib/map.world.js b/src/app/panels/map/lib/map.world.js old mode 100755 new mode 100644 diff --git a/src/app/panels/map/lib/test.js b/src/app/panels/map/lib/test.js new file mode 100644 index 000000000..712ee77c3 --- /dev/null +++ b/src/app/panels/map/lib/test.js @@ -0,0 +1,162 @@ +$.fn.vectorMap('addMap', 'china', { + 'insets': [{ + 'width': 2000, + 'top': 0, + 'height': 800, + 'bbox': [ + { + 'y': -22671671.123330016, + 'x': -40004297.15152583 + }, + { + 'y': 8930392.02513512, + 'x': 40026572.39474938 + } + ], + 'left': 100 + }], + 'paths': { + '103': { + 'path': 'M413.032,414.183l-0.96,1.752c0,0,0.889,0.883,1.98,1.086s1.995-0.493,1.995-0.493L413.032,414.183zM413.032,414.183l-0.96,1.752c0,0,0.889,0.883,1.98,1.086s1.995-0.493,1.995-0.493L413.032,414.183z', + 'name': 'Macao' + }, + '21': { + 'path': 'M329.934,230.111l0.24-5.476l1.785-2.499l-0.832-2.62l-9.168-3.454l0.594-3.691l2.858-4.049l-1.786-6.19l-0.835-0.952l-5.954,4.049l-2.855,9.168l-0.953,6.31l-4.762,3.93l-2.859,1.189l-3.438,0.779c0,0,9.184,11.236,7.729,9.458c-1.455-1.78,1.664,7.146,1.664,7.146l-0.834,3.449l5.357,2.859v2.262l4.881,1.19h1.43v-4.048l3.691-0.597l0.951-4.763l-2.619-2.026l-2.023-2.021l0.832-9.163l2.023-1.073l3.453,1.43L329.934,230.111z', + 'name': 'Ningxia' + }, + '30': { + 'path': 'M391.37,382.632l2.265-1.666v-3.45l1.188-1.072l2.859,0.235l4.879,2.264l0.834-1.667l-1.188-2.025l0.354-1.427l3.098-2.619l5.478,1.427l3.096-1.905l2.264,2.265l5.478-1.429l1.07,2.021l-1.666,2.264l-2.859,4.288v1.069l1.67,1.192l11.43-4.525l4.048,2.264l1.19-1.191l-1.19-2.499l0.28-1.663l7.459,1.663l1.431,1.072l2.022-0.24l3.094,3.929l3.451,7.502l-2.26,1.667l-2.023,3.689l-1.786,0.596l-1.664,3.455l-5.716,2.854l-2.266-1.188l-1.426,2.382v0.833h-1.787h-3.098l-2.857,2.023l-2.021-1.188l-2.5,1.663l-6.314,2.619l-5.121-4.05l-0.354,3.217l1.788,4.882l-4.646,1.904l-2.498,3.452l-4.887,1.191l-2.617,1.073h-5.119c0,0-0.869,2.545-3.453,3.452c-2.584,0.904-9.168,3.213-9.168,3.213l-4.522,3.098l-2.265,2.263l4.287,6.903l-2.856,2.501l-3.451-0.238l-4.053-7.381l0.954-5.238v-2.501l2.854-4.646l3.695-0.831l-0.355-2.501l3.809-1.785l0.476-4.288l6.668-5.119l-0.355-6.905l5.119-6.547l-0.24-2.5l1.666-2.381L391.37,382.632z', + 'name': 'Guangdong' + }, + '15': { + 'path': 'M196.462,200.108l-1.43-16.55l0.836-3.453l4.879-2.262c0,0,5.209-5.03,6.903-5.717c1.696-0.686,10.6-4.285,10.6-4.285l4.285-2.025v-4.047l1.905-2.262l1.788,0.237l7.144,1.192l-0.358,3.095l1.43,4.88l-0.834,7.978l6.072,8.929l3.097,2.026l4.883-3.812h10.237l2.623,0.953l1.429,2.264l-1.193,2.499l-5.714,4.645l0.597,2.261l6.549,4.882h2.618l0.834,1.07l-0.596,2.025l4.05,3.217l9.404,1.429l4.525-1.19l5.718-5.719l6.903,0.598l2.855,4.287l-1.664,3.929l0.475,2.382l-3.688,2.263l-1.668,2.024l0.596,4.763l6.545,4.646l2.875-0.653l7.725,9.458l1.668,7.145l-0.834,3.451l5.357,2.859v2.26l4.883,1.192h1.426v-4.05l3.693-0.595l0.951-4.763l-2.619-2.026l-2.025-2.021l0.834-9.166l2.023-1.071l3.453,1.43l1.432-0.598l0.834,1.667l9.166,4.639l4.883,3.1l0.832,2.856l-2.619,3.691l1.431,4.285l-0.834,2.021l-6.785,0.6l-1.433,0.833l0.478,1.191v1.903l-5.355,0.594l-2.856-1.428h-3.691l-0.596,0.834l0.596,2.024l-1.789,2.023l-0.592,2.262l3.449,2.857l-2.498,5.119l1.072,2.622l-0.238,1.188h-4.051l-2.854,1.435l2.26,3.091l-1.428,4.051l-4.287,1.07l0.357,2.023l-1.189,1.428l-7.383-0.596l-2.854-2.021l-0.601-4.525l-1.664-1.669l-2.62,1.669l-4.523-4.521l-3.455-2.385l-0.354-3.335l-1.074-2.619h-1.787l-7.144,3.096l0.356,3.454h-2.618l-4.287-4.288l-4.525-0.593l-1.786-2.499l1.431-2.86l2.617,2.5l3.097,0.954l2.62-2.025v-4.881l2.857-2.62l2.265-2.263l-1.073-2.856l5.716-4.522l0.832-7.147l-2.619-3.688l-1.429-6.071l-7.144-9.405l-3.692,1.431l-5.118-4.524l-6.907-4.287l-2.856-6.905l-5.359,2.023l-9.999-6.309l-4.883,2.616l-7.501-1.188l-5.714,3.452l-3.691,0.237l-5.715-3.451l-3.93-2.265L196.462,200.108z', + 'name': 'Gansu' + }, + '16': { + 'path': 'M305.646,387.87l3.688,0.241l4.051-3.694l1.668,1.072l7.737,3.216l1.429-0.835l0.235-2.619l1.433-1.429l10.955-7.145l1.903,2.266l6.668,2.021l3.691-4.883l1.666,1.192h2.619v-1.431l3.453-1.192v-1.069l1.43-1.428l0.832,0.236l3.453-3.451l2.856,0.832l2.857-3.931l1.432,3.099l0.832-0.238l4.525-4.288l1.188,0.24l2.021-1.073l3.693,1.073v4.048l2.856,0.595l-0.832,3.929l-2.623,4.29l-1.188,3.688h1.188l3.101-2.854l2.616,5.713l2.025-1.43h2.26l1.666,5.717l-1.666,2.383l0.24,2.5l-5.119,6.547l0.355,6.905l-6.668,5.12l-0.476,4.285l-3.809,1.787l0.354,2.5l-3.694,0.831l-2.853,4.646l-7.502,1.071l-3.93-2.856l-4.049-1.669l-4.049,4.05l-4.158,0.241l-4.058,0.234c0,0-10.996-6.139-9.168-5.119c1.828,1.021-1.666-4.526-1.666-4.526l2.261-4.646l-2.617-1.902h-3.455l-0.832-0.952l-3.691,0.952l-3.692-2.62l1.432-4.048l2.855-0.235l1.069-0.834l0.957-3.69l-1.192-2.024l-9.765-1.785l-1.668-2.856h-2.854h-2.619l-1.906-3.099L305.646,387.87z', + 'name': 'Guangxi' + }, + '01': { + 'path': 'M423.637,253.208l2.024-0.597l6.312,2.621c0,0,1.768,2.299,2.861,2.856c1.092,0.557,5.118,1.43,5.118,1.43l2.021,1.667l2.858-0.479l0.599,1.072l-0.957,6.074l2.858,1.666l1.189,2.263l4.287,0.831l1.666-2.854l2.621,0.356l1.666,2.265l-0.24,2.021l-5.121,0.596v2.264v1.665l-2.021,2.265l1.43,2.618l4.287,2.856l0.237,3.454l8.572,0.832v4.525l-1.666,2.381l1.191,2.263l-0.951,1.43l-3.338,0.594l-1.428,1.906l0.235,4.882l-4.285,6.072l-0.715,0.683l-2.381-2.111H446.5l-2.498-2.855l-4.884,4.761l-1.786-0.834l2.026-3.69l-0.24-1.188l-1.786-0.479l-5.718,3.099l-5.356-10.241l1.666-3.214l-0.595-1.071l-2.858-0.952l-4.76-2.858l1.903-3.928l2.855-1.43l0.598-3.214l-1.07-5.716l-0.596-0.479l-2.856,2.86c0,0-5.978-4.647-4.287-3.453c1.69,1.192-3.217-4.049-3.217-4.049l3.217-2.261l0.834-4.05l2.021-1.431l-0.354-5.359l1.43-1.188l2.619,1.787l1.664,2.26l3.453-2.26l1.192-1.434l-0.598-2.617l-4.049-2.263L423.637,253.208z', + 'name': 'Anhui' + }, + '102': { + 'path': 'M417.745,409.005l3.394,0.773l3.453-2.558l1.666,4.582c0,0-5.521,2.673-3.691,1.785c1.828-0.884-4.641-0.355-4.641-0.355l-0.834-3.454L417.745,409.005z', + 'name': 'Hong Kong' + }, + '07': { + 'path': 'M435.945,374.779c0,0,2.881-12.508,1.742-10.365c-1.137,2.144,1.672-2.62,1.672-2.62l0.83-2.854l2.023-4.286l-1.072-1.668l0.24-3.691l4.881-5.475l-0.357-3.691l3.215-5.478l3.095,0.834l6.311-4.524l1.193-2.26l3.69,0.593l2.025,5.118l1.666,3.454h4.047l2.498-3.215l3.693,3.69l6.454-2.276l-4.069,9.776l-2.385-1.192l-1.666,0.835l-0.238,0.954l2.262,2.501l-0.598,8.929l0.598,2.859l-0.598,0.834l-2.617-0.599l-1.668,1.667l1.191,2.384l-3.214,3.095l0.595,1.189l-3.097,1.665l0.478,2.264l-1.072,1.191h-4.285l-2.264,2.025l-0.357,0.832l2.023,1.428l-2.26,3.452l-2.859,3.691l-1.189-0.356l-3.1,3.216l-3.447-7.502l-3.098-3.929l-2.023,0.24l-1.43-1.072L435.945,374.779z', + 'name': 'Fujian' + }, + '22': { + 'path': 'M421.139,189.75l-0.357-2.856l-0.832-1.905l5.095-2.126l0.381-1.683l-1.189-4.767h-1.668l-6.666-3.449l-3.69,3.69c0,0-1.125,6.585-0.832,4.88c0.289-1.704-3.693,4.288-3.693,4.288l-0.594,4.286l0.832,2.263l4.881-0.834l3.693,1.071l1.784-1.667L421.139,189.75z', + 'name': 'Beijing' + }, + '09': { + 'path': 'M371.131,276.068l9.405,8.336l7.742,1.665l7.144-1.072l2.262,1.072l2.5-1.43l1.783,1.787l0.834,2.856l3.455,1.905h4.524l3.451,2.857l3.098-1.428l2.382,1.428l1.903-3.929l2.855-1.43l0.598-3.216l-1.07-5.715l-0.596-0.479l-2.856,2.86l-4.287-3.453l-3.218-4.049l3.218-2.263l0.834-4.048l2.021-1.431l-0.354-5.359l1.43-1.188l2.619,1.787l1.664,2.26l3.455-2.26l1.19-1.434l-0.598-2.617l-4.049-2.263l-0.834-2.619l-7.142,0.835l-4.524-3.93l-2.021-0.596v-2.621l10-11.074l-3.69,0.834l-2.261,1.669l-0.957-1.429v-1.666l-1.663-0.6l-4.525,1.785l-11.43-1.428l-0.597,9.408c0,0-6.604,5.169-5.479,4.287c1.129-0.884-7.381,1.429-7.381,1.429l-10.359,7.142l-8.215,2.264v1.43l7.738,11.666L371.131,276.068L371.131,276.068z', + 'name': 'Henan' + }, + '29': { + 'path': 'M313.622,349.296l-0.836-2.858l-2.618-0.954l-4.283,2.622l-2.859-1.432l-0.238-3.688l-1.43-1.79v-1.903l-4.049-0.952l-1.07,1.188l0.599,2.859l-3.217,1.43l-0.834,2.021l0.834,2.5l-7.146,8.336l1.191,9.766l-3.453,2.854l-1.666-1.784l-6.907,4.048l-2.618-1.431c0,0-11.535-22.106-10.002-19.172c1.533,2.938-3.931-2.854-3.931-2.854l-3.213-0.834l-1.432-2.619l1.787-2.859l-2.857-2.263l-3.455,2.859l-3.451,0.598l-2.263-10.363l-0.596-2.499l-3.454,4.286l-1.427,0.831l0.356,6.551l-0.834,1.431h-1.784l-1.43-1.431l-1.667,2.026l1.667,7.381h2.024l1.667,1.19c0,0,0.468,2.396,0.594,4.521c0.125,2.125-0.833,15.719-0.833,15.719l-10.837,9.766l-0.594,3.689l-2.024,1.787l-0.238,1.903l1.669,4.643l-1.431,3.454l0.834,0.478l5.478-1.433l7.738-0.476l-0.834,3.098l1.431,2.857l0.475,4.287l0.955,1.426l4.524,0.243l2.024,1.425l-2.264,2.856l-0.356,3.453l-1.667,4.05l1.068,1.43l2.86,0.238l4.881,1.784l-0.593,1.667l3.212,4.881h4.524l5.716-3.213l1.786,0.952v1.906l0.832,2.856l1.432,1.429l3.092-0.477l1.192,0.834l1.072-1.192v-4.525l-1.906-8.333l1.431-2.5h4.762h1.192l2.62-3.213l6.783,2.261l2.858-2.503l1.431,1.432l2.858-1.786l2.615,2.618h1.073l0.953-1.428l2.261-2.263l1.073,0.833l3.213-0.595l3.099-2.502l2.619-3.811l3.688-0.831l2.023,2.021l1.43-4.048l2.857-0.235l1.069-0.834l0.957-3.691l-1.192-2.023l-9.765-1.785l-1.668-2.857h-2.854h-2.619l-1.906-3.097l0.24-1.665l1.188-6.907l-3.809-3.689l2.859-12.027l-1.908-1.667l-6.309,1.906l-1.431-2.501v-2.856l-1.428-1.43l3.094-4.286l3.453,1.07l1.43-1.429l6.313,0.951l2.856-0.951L313.622,349.296z', + 'name': 'Yunnan' + }, + '13': { + 'path': 'M153.889,69.508l2.327-0.014l-1.428,4.525l2.025,2.38l0.236,1.666l4.525,4.524l1.191,3.453l5.953,0.357l2.62,2.265h1.429l3.453,7.379l3.451,8.931l-1.784,5.357l0.358,2.025l-3.215,5.477l0.833,4.286l11.192,4.763l12.025,1.788l12.503,8.571l4.049,1.429l0.237,2.261l2.619,5.478l2.619,7.146l3.333,5.953l-1.903,2.263v4.047l-4.286,2.026l-10.596,4.284l-6.907,5.719l-4.881,2.26l-0.834,3.453l1.43,16.55l-3.931-0.596l-1.783,1.431l-26.315,5.119l-3.691,2.856l0.358,6.906l7.978,6.548l-2.62,4.286l-3.69,1.668l-0.597,2.024l0.835,2.259h2.021l1.192,1.429l-7.738,2.617l-4.525-1.667l-2.382-1.424h-5.715l-10.24-4.642h-6.546l-5.121,1.428h-5.714l-8.931,4.879l-7.143-0.834l-7.145,2.5l-5.956-1.907l-3.689-3.211l-9.525-1.427l-6.191,4.28l-3.452-1.425l-2.858-2.263l-6.907-1.667l-1.07-1.189l-2.857-0.237l-9.782,5.945l-10.037-1.25l-0.822-0.359l1.113-8.623l-4.524-1.191l-9.406-6.902l-2.62-0.241l-2.023-4.525l1.427-4.643l-0.477-2.26l-3.451-2.266l-1.192-2.26l-7.143-4.049v-1.189l3.452-1.431l2.023,1.19l2.025-2.025l-0.598-6.785l0.598-5.716l-4.646-4.642l-3.095,0.833l-1.189-3.336l1.785-3.452l-0.952-3.214l3.038-2.749l1.248-1.182v-2.618l4.285-2.024l4.286-0.833l3.811-1.429l3.099,0.832l2.26-0.832l0.833,0.595l0.356,2.859l2.022,0.832l4.765-0.238c0,0,3.566-4.729,5.478-6.073c1.911-1.346,11.19,2.381,11.19,2.381l5.717-4.048l16.552-3.689l1.069-2.264l1.43-6.31l4.643-3.69h1.433v-1.906l0.236-15.836l0.833-3.212l-4.521-1.668l-0.24-1.191l4.762-1.428l12.384-1.073l1.905,2.501l4.287,0.952l1.192,0.239l1.665-2.262l-2.265-2.263l9.169-18.574l1.431-0.953l8.335,4.047h3.689l1.667,2.264l7.979-2.502l2.023-13.212l3.452-2.265l4.048-0.238l2.859-3.452l1.071-3.454l2.263-1.191L153.889,69.508z', + 'name': 'Xinjiang' + }, + '26': { + 'path': 'M363.393,259.519l-1.428-3.454l2.498-8.81l-3.689-16.903c0,0,3.262-5.777,2.619-4.286c-0.646,1.49,1.07-3.929,1.07-3.929l-3.334-6.905l3.096-4.884l0.594-4.525l1.67-3.452l-0.238-4.046l-1.432-1.074l-2.26,2.502l-6.072,0.356l-3.096,4.526l0.236,2.62l-0.593,1.665l-2.502,0.834l-9.406,13.454l-1.19-0.836l-2.617-0.594l-5.359,0.359l-1.789,2.499l-0.233,5.478l0.834,1.667l9.166,4.637l4.883,3.099l0.832,2.855l-2.619,3.691l1.431,4.286l-0.835,2.021l-6.784,0.6l-1.433,0.835l0.478,1.188v1.904l-5.355,0.596l-2.856-1.428h-3.691l-0.596,0.832l0.596,2.026l-1.789,2.022l-0.592,2.261l3.451,2.861l-2.5,5.117l1.071,2.619l-0.237,1.191h-4.052l-2.854,1.429l2.262,3.098l-1.43,4.048l2.383,0.478l0.238,2.617l2.021,0.237l7.386-1.427l1.43,0.593l0.354,2.025l3.099,0.835l6.547,3.216l3.69-1.434l8.097,2.857l1.666,2.26l4.051-0.829l-0.596-4.288l-0.834-1.191l0.834-3.451l4.286-2.021l1.068-1.668l-2.26-0.837l-2.5-0.593l-2.619-2.62l1.189-1.068h8.571h1.908l1.189,0.83l2.616-2.022v-3.454l-7.737-11.668L363.393,259.519L363.393,259.519z', + 'name': 'Shaanxi' + }, + '19': { + 'path': 'M491.15,173.2l6.783-10.002l4.287-4.881l-0.595-4.763l-4.524-5.239l-0.594-4.286l-8.216-11.075l-0.358,1.074l-1.666,1.786l-3.453-4.05l-4.883-1.429l-0.236,1.429v2.264l-2.022,2.022l-4.047,4.05H467.1l-1.666,2.856h-1.789l-3.094,3.096h-1.787l-3.691,3.691l-2.262,0.596l-4.881,7.5l-3.096-4.644l-3.453-2.262l-1.666,1.667l1.903,10.002l-1.666,3.453l-1.668,5.12l4.763,3.215l2.621,0.238l3.45,4.881l2.5-1.429c0,0,2.857-2.881,4.05-4.882c1.192-2.002,4.049-6.788,4.049-6.788l6.787-1.429l4.287,4.286l-3.099,6.787l-4.049,6.311l3.688,2.62l-0.233,3.098l-2.857,2.855l0.597,1.19l4.881-2.619l7.143-9.407l10.836-6.072L491.15,173.2z', + 'name': 'Liaoning' + }, + '32': { + 'path': 'M279.33,280.95l1.788-4.05l-2.025-2.261l-0.357-3.454l7.145-3.096h1.787l1.069,2.619l0.357,3.336l3.455,2.384l4.522,4.521l2.621-1.669l1.664,1.669l0.6,4.525l2.855,2.021l7.383,0.599l1.189-1.431l-0.357-2.023l4.287-1.07l2.381,0.478l0.238,2.617l2.024,0.237l7.382-1.427l1.43,0.593l0.354,2.026l3.099,0.834l6.549,3.214v7.47l-3.932,1.059l-1.351,7.671l-5.346,3.72l-1.014,5.811l-4.564-2.092l-5.58,2.092l-0.231,4.416l-0.464,4.53l6.507,4.07l2.28,6.977l-2.623,0.833l-3.928-2.263l-3.213,3.691v1.666l6.311,3.452l1.427,2.62l-4.523,1.666l-6.904-0.238l-0.831-2.855l-2.621-0.954l-4.285,2.623l-2.859-1.429l-0.238-3.694l-1.43-1.786v-1.903l-4.047-0.952l-1.072,1.188l0.599,2.858l-3.215,1.431l-0.836,2.021l0.836,2.504l-7.146,8.334l1.191,9.764l-3.453,2.855l-1.666-1.784l-6.906,4.049l-2.621-1.431l-10.001-19.17l-3.931-2.854l-3.216-0.835l-1.428-2.623l1.787-2.854l-2.857-2.264l-3.455,2.858l-3.45,0.595l-2.264-10.359l-0.597-2.499c0,0-2.04-22.568-0.594-16.55c1.446,6.017-3.099-8.336-3.099-8.336l2.267-1.665l-6.55-12.027l-7.977-6.311l1.069-3.692l0.953-1.188l11.669-1.666l7.738,2.262l4.523-1.431l1.785,2.859l5.717,5.715l4.524-0.833v-3.453l1.191-2.266l4.522-1.783l1.667,2.856l2.621-1.903l3.689,0.478v-0.241H279.33z', + 'name': 'Sichuan' + }, + '05': { + 'path': 'M544.896,113.042l-2.07-0.088h-2.858l-4.285-1.431l-1.43-2.619l-1.431,2.024l-2.022-1.428l-4.523,5.12l-0.834,1.427l-2.022,0.357l-2.859-3.214l-2.621-1.072l-2.854-5.715l-2.027,1.431l0.594,5.12l-1.426,0.833l-3.689-4.05l-1.432-1.903h-2.854l-1.666-4.288l-3.813-2.023l-5.354,2.023l-2.025-0.357l-3.098-3.094l-4.285,2.5h-2.383l-2.857,1.191l-4.285-3.096l-2.854-5.24l-6.787,1.189l-2.621,3.099l-0.238,3.45l-7.502-2.023l-1.074,2.381l0.601,1.667l3.928,2.859v4.046l0.594,3.929l2.265,3.456l0.356,3.095l1.666,1.191l5.717-5.479l5.953,7.502v4.288l3.213,1.667l0.238-1.431l4.885,1.431l3.451,4.046l1.666-1.784l0.357-1.074l8.217,11.075l0.594,4.286l4.527,5.239l0.592,4.761l4.051-2.499l3.689-10.598l1.67-0.595l4.047,2.263l6.549-0.834l2.26-2.024l-3.092-4.763l0.832-1.191c0,0,7.84-2.611,6.072-2.022c-1.766,0.588,2.5-4.883,2.5-4.883l3.215-1.428l0.238-4.766l0.832-3.212l1.785-0.596l1.668,1.789l1.668,1.426l4.287-5.715l1.188-4.288L544.896,113.042z', + 'name': 'Jilin' + }, + '04': { + 'path': 'M483.646,282.616l-1.426,4.286l-1.898,2.251l-3.225,3.824l-4.879-0.835l-3.929-2.383l-2.383,1.19l-8.571-0.832l-0.238-3.454l-4.287-2.856l-1.428-2.618l2.02-2.264v-1.665v-2.267l5.121-0.594l0.24-2.023l-1.666-2.263l-2.621-0.355l-1.666,2.854l-4.287-0.831l-1.188-2.263l-2.857-1.666l0.955-6.074l-0.598-1.072l-2.859,0.479l-2.021-1.667l-5.118-1.429l-2.861-2.857l-6.307-2.621l0.592-2.856l2.5-1.069l4.645,3.927h1.433l4.284-0.476l2.5-2.022l3.453,2.856l1.427-2.62l0.358-1.43l2.857-1.667l0.834-3.45l2.854-0.597l7.148,4.881c0,0,3.365,0.754,5.117,2.025c1.754,1.271,9.766,16.313,9.766,16.313l-0.357,1.666l6.548,3.095l1.784,2.859l3.099,1.429l1.428,2.855l-2.023,0.951l-3.334-1.188h-4.645l-4.287-1.432l-1.666,1.432l3.932,1.188l3.813,1.669L483.646,282.616z', + 'name': 'Jiangsu' + }, + '06': { + 'path': 'M153.954,234.989l4.523,1.667l7.742-2.617l-1.193-1.429h-2.021l-0.834-2.259l0.594-2.024l3.692-1.668l2.617-4.286l-7.977-6.548l-0.356-6.906c0,0,2.08-2.545,3.689-2.856c1.609-0.313,26.317-5.119,26.317-5.119l1.783-1.428l3.931,0.594l13.215,3.095l3.93,2.265l5.714,3.451l3.692-0.237l5.714-3.452l7.501,1.188l4.882-2.616l9.999,6.309l5.36-2.023l2.856,6.903l6.907,4.286l5.119,4.527l3.691-1.431l7.146,9.405l1.426,6.071l2.619,3.688l-0.832,7.146l-5.715,4.524l1.073,2.856l-2.265,2.263l-2.856,2.62v4.879l-2.621,2.027l-3.097-0.954l-2.617-2.5l-1.431,2.859l1.787,2.499l4.524,0.594l4.287,4.288h2.618l2.024,2.265l-1.787,4.046v0.239l-3.688-0.479l-2.621,1.905l-1.666-2.856l-4.524,1.785l-1.19,2.264v3.451l-4.524,0.836l-5.715-5.716l-1.787-2.856l-4.524,1.428l-7.738-2.262l-11.67,1.666l-0.952,1.189l-1.071,3.69l-2.263,1.43l0.238,3.692l-6.906,8.931l-11.43-2.383l-0.833-4.285l-7.146-5.718l-15.717-2.498l-6.786-1.19l-2.621-0.238l-5.953-4.883l-12.384-2.857l-8.57-16.551l-0.238-4.642l3.451-1.672v-5.117l2.502-6.313l-2.858-2.856L153.954,234.989z', + 'name': 'Qinghai' + }, + '31': { + 'path': 'M385.895,447.523l-5.119,8.93v3.929l-10.238,8.336l-10.598-3.689l-2.025-7.501l0.597-3.454c0,0,8.074-8.075,5.715-5.716c-2.357,2.358,2.025-1.665,2.025-1.665l9.403-1.668l4.289-0.358l1.426-1.666l3.103,0.832L385.895,447.523z', + 'name': 'Hainan' + }, + '23': { + 'path': 'M484.32,292.485l-3.998-3.332c0,0,0.867-0.375,1.898-2.251c1.031-1.875,1.426-4.286,1.426-4.286l4.287,1.788l2.027,2.854l-1.433,2.024L484.32,292.485z', + 'name': 'Shanghai' + }, + '10': { + 'path': 'M413.04,235.229l0.357-1.426l-1.783-3.453l6.902-12.5c0,0,8.725-7.9,6.313-5.718c-2.411,2.185,4.523-1.188,4.523-1.188l4.268-5.423l-1.647-1.125l-1.56-3.907l-3.319,1.286l-5.479-1.428l-0.237-1.428l-0.238-9.17l3.69-1.667l-0.419-1.563l-0.177-0.104l0.81-3.557l-5.094,2.128l0.832,1.905l0.178,1.424l0.18,1.433l-2.857,1.19l-1.785,1.667l-3.692-1.071l-4.881,0.834l-0.832-2.264l0.594-4.287l3.693-4.286l0.831-4.88l3.691-3.691l6.666,3.454h1.668l1.189,4.762l1.905,0.95l0.953,3.1l-0.356,2.024l4.047,2.854l0.594,2.264l3.338,1.428l8.332-4.523v-2.621l4.883-7.143l-3.45-4.881l-2.621-0.238l-4.763-3.218l1.668-5.118l-7.387-0.595l-3.213-4.765l0.357-2.619l-6.31-6.906l-4.051,2.026l-3.451,3.452l1.191,2.62l-0.834,1.667l-4.882,0.237l-2.264,2.022l-2.022-0.835l-2.021,2.026l-4.527,3.453l-2.024-1.43v-4.644l-1.666-0.832l-2.619,1.189l-3.096,6.547l-1.189,6.311l3.689,6.19l3.215,2.858v5.24l1.904,4.286l-0.834,4.764l-4.884,3.213l-2.26,7.382l4.049,4.645l2.857,5.717l-1.785,2.857l-0.477,3.928l-1.787,2.619l-0.834,2.859l2.621,3.446l11.43,1.431l4.524-1.787L413.04,235.229z', + 'name': 'Hebei' + }, + '08': { + 'path': 'M464.838,96.639l6.787-1.19l2.854,5.241l4.285,3.095l2.856-1.188h2.386l4.285-2.501l3.094,3.094l2.024,0.357l5.357-2.023l3.813,2.023l1.666,4.288h2.857l1.43,1.904l3.689,4.049l1.426-0.833l-0.594-5.12l2.026-1.432l2.854,5.716l2.621,1.074l2.858,3.212l2.021-0.357l0.836-1.427l4.523-5.12l2.022,1.428l1.43-2.022l1.431,2.619l4.283,1.429h2.86l2.07,0.088l-1.238-2.113l-0.598-6.906l-5.115-7.978l2.855-2.857l2.616-4.883h9.646l1.785-1.665l-0.597-3.69l2.025-3.691l-0.596-2.024l0.832-3.451l-0.236-17.742l2.855-5.715l-3.214-3.692l0.595-2.261l-1.427-2.024l-3.69,1.429l-4.289,4.884l-4.283,2.023l-4.289,5.951l-10.598,3.692l-4.879-3.692l0.594-2.262l-2.5-3.689l-1.191-3.811l-4.047-0.239l-7.145-3.69l-2.859,1.071l-3.33-1.667l-4.887,0.834l-4.283-1.429l-2.621-3.69l-2.498-2.857l-0.951-2.857l-3.334-3.452l-2.026-3.099l-4.644-6.31l-1.428-3.69l-5.119-6.548l-1.432-3.454l-6.549-3.216l-4.287,1.429l-3.689-0.833l-8.336-1.668l-11.07,3.932l-2.024,1.786l2.262,3.096l-2.856,7.499l0.834,0.835l4.881,3.096l2.621-4.286l4.524,2.856l-0.235,2.022l1.664,5.119l2.854,3.218l5.717,0.833l1.668-1.787l3.451-0.477l6.547-5.476l8.576,6.31l-2.858,11.669l0.594,8.333v5.119l-2.26,1.191l-0.238,13.335l-0.597-0.476l-2.26-2.858h-1.192l-0.595,1.073c0,0-8.797,13.044-7.146,10.596c1.652-2.448-3.451,4.523-3.451,4.523l0.357,1.428l7.145,4.886l3.926-1.071l0.599,1.071l-0.834,1.189l-3.689,1.667l-0.359,3.214L464.838,96.639z', + 'name': 'Heilongjiang' + }, + '24': { + 'path': 'M363.393,259.519l8.217-2.265l10.357-7.142l7.381-1.431l5.477-4.287l0.599-9.405l-2.623-3.449l0.836-2.856l1.787-2.619l0.477-3.929l1.785-2.86l-2.859-5.713l-4.047-4.645l2.262-7.383l4.886-3.212l0.83-4.765l-1.904-4.286v-5.242l-3.215-2.854l-7.381,3.809l-1.191-1.189l-3.93,2.855l-3.213-0.235l-6.312,9.048h-1.906l-3.452,2.858l0.237,4.046l-1.67,3.452l-0.594,4.525l-3.096,4.884l3.334,6.905l-1.07,3.929l-2.619,4.286c0,0,4.146,18.996,3.689,16.903s-2.498,8.81-2.498,8.81L363.393,259.519z', + 'name': 'Shanxi' + }, + '14': { + 'path': 'M152.525,339.529l6.787,0.834l2.265,3.216l1.189,0.477l10.239-1.904l0.594-1.787l2.023-1.07l4.884-4.05l4.285-0.594l3.93-2.501l7.74-4.286l0.832,1.428l5.716,1.904l8.334-4.285l2.618,1.787l-2.379,3.452l0.952,0.833h3.332l0.359,1.427l-2.857,5.121l0.833,0.834h1.666l8.336,2.265l3.691-3.099l5.478,4.289l1.667-2.026l1.43,1.431h1.784l0.834-1.431l-0.356-6.549l1.429-0.835l3.451-4.284l-0.594-16.549l-3.099-8.337l2.265-1.665l-6.548-12.027l-7.979-6.311l-2.26,1.43l0.238,3.692l-6.908,8.931l-11.428-2.384l-0.833-4.286l-7.146-5.716l-15.717-2.498l-6.787-1.188l-2.619-0.241l-5.952-4.883l-12.385-2.857l-8.57-16.551l-0.238-4.642l3.451-1.672v-5.117l2.502-6.311l-2.858-2.858l3.811-3.095l-2.383-1.425h-5.716l-10.238-4.644h-6.549l-5.118,1.43h-5.715l-8.931,4.879l-7.144-0.834l-7.146,2.5l-5.954-1.906l-3.688-3.212l-9.526-1.427l-6.192,4.28l-3.45-1.425l-2.859-2.263l-6.908-1.667l-1.065-1.189l-2.857-0.237l-9.782,5.945l-10.412-1.297l2.428,4.398l2.68,1.995l-0.821,3.842l-0.231,3.758l0.256,2.672l0,0l-0.193,3.208l3.451,3.454l0.239,4.884l-1.072,1.907l-5.119,0.591l-2.621-2.854l-2.619,0.355l-0.476,2.265l1.428,3.688l0.479,2.62v3.333l-0.833,2.381l0.354,1.909l3.336,0.356l1.785,3.094l7.739,6.071v1.906l5.716,6.311l1.902,2.262l1.79,0.595l3.451-3.451l3.096,2.856c0,0,15.395,13.684,13.098,11.193c-2.297-2.491,2.381,5.715,2.381,5.715h2.859l1.667-1.665l1.426,1.428v5.117l7.741,4.287l1.667-0.357l1.191,4.287l6.548,3.81l0.238,2.501l1.188,0.835l5.717-0.24h3.098l4.644,3.457l10.24-0.359l5.476-0.239l1.428,2.265l-1.188,4.883l1.427,1.664l5.715-4.761l7.146-5.239l5.12,0.95L152.525,339.529z', + 'name': 'Xizang' + }, + '28': { + 'path': 'M430.413,200.491c0,0-1.832,1.672-3.319,1.284c-1.49-0.388-5.479-1.428-5.479-1.428l-0.237-1.429l-0.238-9.169l3.69-1.667l-0.596-1.666l0.81-3.557l0.385-1.683l1.901,0.95l0.953,3.098l-0.356,2.022l4.047,2.858l0.594,2.263l-2.379,1.668l-0.834,3.809L430.413,200.491z', + 'name': 'Tianjin' + }, + '18': { + 'path': 'M313.622,349.296l-1.666,4.761l-2.856,0.951l-6.313-0.951l-1.43,1.429l-3.453-1.07l-3.094,4.286l1.428,1.43v2.856l1.431,2.501l6.309-1.906l1.908,1.667l-2.859,12.027l3.81,3.689l-1.188,6.907l3.688,0.238l4.051-3.695l1.668,1.073l7.737,3.216l1.429-0.832l0.235-2.622l1.433-1.429l10.955-7.144l1.903,2.265l6.668,2.021l3.689-4.883l1.668,1.192h2.619v-1.432l3.453-1.189v-1.071l1.43-1.428l0.832,0.237l3.453-3.452l-2.857-5.123l1.429-7.142l-1.785-2.263l-5.121,1.428l-0.596-0.834l5.717-6.309l-2.5-10.001l-3.81,2.855l-3.334-3.45l-3.215-4.29l-0.24-2.619l-2.26-0.477l-2.621,0.834l-4.287-2.024l-2.022,4.883l-3.691,0.239l-2.619,4.049l-1.666-0.834l-2.623,0.834l-3.928-2.266l-3.213,3.69v1.668l6.312,3.453l1.426,2.621c0,0-6.094,2.245-4.523,1.667C322.1,348.955,313.622,349.296,313.622,349.296z', + 'name': 'Guizhou' + }, + '101': { + 'path': 'M505.438,371.203l-3.217,19.169l-1.664,6.07v5.123l-1.43,1.427l-3.451-5.119l-3.693-2.858l-3.215-8.571c0,0-0.451-5.62,0.357-7.74c0.809-2.118,5.356-14.05,5.356-14.05l6.313-5.357l4.051,1.904L505.438,371.203z', + 'name': 'Taiwan' + }, + '12': { + 'path': 'M356.486,329.29l1.787-4.048l5.119-4.287l4.881,2.026l3.096-2.026l-2.621-3.093l1.429-1.433l13.219,0.836l4.525,3.097l2.264,1.425l3.451-2.26l2.619-0.833l0.596,3.093h1.904l1.43-2.021l2.856-2.86l1.431,2.027v4.049l1.19,1.667l2.619,0.594l2.855-2.854l4.287-1.433l7.979-7.381l3.691,0.236l4.522-1.428l-5.358-10.24l1.668-3.214l-0.593-1.071l-2.862-0.952l-4.761-2.858l-2.381-1.427l-3.098,1.427l-3.451-2.854h-4.524l-3.455-1.907l-0.83-2.856l-1.787-1.786l-2.5,1.428L395.421,285c0,0-9.509,0.927-7.146,1.071c2.363,0.146-7.736-1.666-7.736-1.666l-9.407-8.334l-2.619,2.023l-1.188-0.831h-1.907h-8.572l-1.189,1.068l2.619,2.62l2.5,0.593l2.26,0.837l-1.067,1.668l-4.287,2.021l-0.834,3.451l0.834,1.191l0.596,4.288l2.5,0.238l2.619,3.452l1.07,6.548l-0.832,2.262l-1.666-0.594l-4.883,3.812l-8.336,1.429l-2.261,2.263l1.783,2.262l0.24,4.882l2.262,0.598L356.486,329.29z', + 'name': 'Hubei' + }, + '25': { + 'path': 'M425.661,252.611l0.597-2.856l2.5-1.069l4.645,3.927h1.433l4.284-0.476l2.5-2.022l3.453,2.856l1.429-2.62l0.356-1.43l2.857-1.667l0.834-3.45l2.854-0.595l7.98-13.454l-1.429-2.264l1.429-1.427l1.666,0.595l2.619-1.429l1.432-3.094l6.545-6.073l5.121-1.666l2.381-2.266l-0.592-4.88l-3.457-0.355l-7.738,0.952l-5.356-2.62l-3.216,0.596l-7.977,10.239l-2.262,1.429l-5.117-2.263l-0.359-2.619l-1.069-4.523l-2.859-1.669l-4.643,1.073l-2.882-1.971l-4.266,5.423l-4.523,1.188c0,0-8.514,7.798-6.313,5.718c2.201-2.081-6.902,12.5-6.902,12.5l1.783,3.45l-0.357,1.431v1.666l0.957,1.429l2.261-1.669l3.69-0.834l-10.002,11.074v2.621l2.023,0.596l4.524,3.93l7.146-0.835L425.661,252.611z', + 'name': 'Shandong' + }, + '33': { + 'path': 'M318.986,317.871l5.58-2.092l4.564,2.092l1.014-5.811l5.346-3.72l1.351-7.671l3.932-1.059v-7.47l3.689-1.432l8.096,2.857l1.666,2.26l4.051-0.829l2.5,0.238l2.619,3.452l1.07,6.548l-0.832,2.262l-1.666-0.594c0,0-3.072,3.501-4.884,3.812c-1.809,0.311-8.336,1.429-8.336,1.429l-2.26,2.263l1.783,2.262l0.24,4.883l2.262,0.597l5.715,7.142l0.357,9.407l-3.218,2.412l-0.592,0.445l-3.334-3.451l-3.215-4.29l-0.24-2.619l-2.26-0.476l-2.621,0.834l-4.287-2.025l-2.022,4.883l-3.691,0.239l-2.619,4.049l-1.666-0.834l-2.28-6.977l-6.507-4.07L318.986,317.871z', + 'name': 'Chongqing' + }, + '03': { + 'path': 'M408.279,325.242l3.336,6.549l0.355,3.452l-1.785,3.454l-2.502,2.024l-0.594,6.188l0.832,0.955l1.43-0.596l0.834,0.596v3.927l1.785,4.647l2.026,0.831l0.234,6.789l-1.193,4.642l1.193,2.021l2.266,2.265l5.474-1.429l1.071,2.022l-1.665,2.263l-2.859,4.287v1.07l1.67,1.192l11.43-4.525l4.047,2.263l1.191-1.19l-1.191-2.499l0.281-1.663l1.742-10.365l1.67-2.62l0.832-2.854l2.025-4.286l-1.072-1.668l0.238-3.691l4.881-5.475l-0.355-3.691l3.213-5.478l3.095,0.834l6.311-4.524l1.193-2.263l-4.049-7.501l-2.619-3.69l1.901-1.818l-2.381-2.111H446.5l-2.5-2.855l-4.884,4.762l-1.784-0.835l2.024-3.69l-0.24-1.188l-1.784-0.479l-5.716,3.099l-4.524,1.429l-3.689-0.238c0,0-9.709,9.669-7.979,7.381c1.731-2.287-4.287,1.433-4.287,1.433L408.279,325.242z', + 'name': 'Jiangxi' + }, + '11': { + 'path': 'M408.279,325.242l-2.619-0.594l-1.188-1.667v-4.05l-1.43-2.026l-2.857,2.86l-1.43,2.023h-1.904l-0.594-3.096l-2.621,0.833l-3.451,2.263l-2.264-1.428c0,0-2.666-2.521-4.525-3.097c-1.857-0.576-13.217-0.832-13.217-0.832l-1.43,1.429l2.62,3.093l-3.096,2.026l-4.883-2.026l-5.117,4.287l-1.787,4.05c0,0-0.19,6.479,0.357,9.405c0.551,2.926,2.5,10.002,2.5,10.002l-5.717,6.31l0.596,0.833l5.121-1.428l1.785,2.263l-1.429,7.144l2.857,5.121l2.856,0.832l2.857-3.931l1.43,3.099l0.834-0.238l4.523-4.288l1.191,0.24l2.021-1.073l3.693,1.073v4.048l2.856,0.595l-0.832,3.929l-2.623,4.29l-1.188,3.688h1.188l3.103-2.854l2.617,5.713l2.021-1.43h2.264l2.263-1.666v-3.45l1.188-1.072l2.859,0.235l4.879,2.264l0.834-1.667l-1.188-2.023l0.354-1.429l3.098-2.619l5.478,1.428l3.096-1.906l-1.193-2.021l1.193-4.642l-0.234-6.789l-2.026-0.831l-1.785-4.647v-3.927l-0.834-0.596l-1.43,0.596l-0.832-0.955l0.594-6.188l2.502-2.024l1.785-3.454l-0.355-3.452L408.279,325.242z', + 'name': 'Hunan' + }, + '02': { + 'path': 'M483.793,336.063l-6.455,2.276l-3.693-3.69l-2.498,3.215h-4.049l-1.666-3.454l-2.023-5.118l-3.692-0.596l-4.047-7.501l-2.619-3.69l1.903-1.818l0.716-0.685c0,0,6.241-8.84,4.286-6.07c-1.954,2.769-0.239-4.882-0.239-4.882l1.43-1.906l3.336-0.594l0.951-1.43l-1.189-2.263l1.666-2.382v-4.524l2.384-1.189l3.928,2.382l4.879,0.835l3.225-3.824l3.998,3.332l-1.744,1.324l-2.021,3.096l-3.217,0.952l-1.074,0.833l3.098,1.666l5.715-2.499l9.406,3.929l0.953,7.979h-3.809l-0.24,2.382l2.024,3.332l-1.784,2.024l2.022,3.214l-3.096,3.69l-1.43-1.787l-4.644,11.788L483.793,336.063z', + 'name': 'Zhejiang' + }, + '20': { + 'path': 'M301.969,226.604l3.438-0.779l2.859-1.188l4.762-3.932l0.953-6.31l2.855-9.168l5.954-4.048l0.835,0.951l1.786,6.19l-2.858,4.049l-0.594,3.691l9.168,3.453l0.832,2.621l5.358-0.359l2.617,0.596l1.191,0.834l9.405-13.454l2.502-0.835l0.593-1.664l-0.236-2.623l3.096-4.523l6.072-0.358l2.262-2.5l1.431,1.074l3.452-2.86h1.904l6.312-9.046l3.215,0.235l3.93-2.855l1.191,1.189l7.381-3.809l-3.689-6.193l1.189-6.311l3.096-6.549l2.619-1.188l1.666,0.832v4.644l2.025,1.43l4.526-3.453l2.021-2.026l2.022,0.835l2.265-2.025l4.881-0.234l0.834-1.667l-1.191-2.622l3.453-3.452l4.049-2.024l6.31,6.908l-0.355,2.618l3.213,4.763l7.385,0.595l1.666-3.453l-1.903-10.002l1.666-1.667l3.453,2.262l3.096,4.644l4.881-7.5l2.264-0.596l3.689-3.692h1.787l3.094-3.095h1.787l1.666-2.856h4.527l4.047-4.051l2.021-2.021v-2.264l-3.213-1.667v-4.286l-5.953-7.502l-5.717,5.478l-1.666-1.19l-0.357-3.096l-2.264-3.453l-0.594-3.931v-4.046l-3.928-2.858l-0.601-1.667l1.074-2.382l7.502,2.022l0.238-3.452l2.621-3.099l-1.789-1.666l0.358-3.214l3.689-1.667l0.834-1.19l-0.598-1.07l-3.927,1.07l-7.145-4.882l-0.357-1.43l3.453-4.524l7.146-10.597l0.594-1.072h1.193l2.26,2.858l0.596,0.479l0.238-13.336l2.26-1.191v-5.121l-0.594-8.333l2.858-11.668l-8.575-6.312l-6.548,5.478l-3.45,0.476l-1.668,1.786l-5.718-0.832l-2.854-3.215l-1.664-5.122l0.236-2.021l-4.525-2.858l-2.621,4.289l-4.881-3.096l-0.834-0.835l2.856-7.5L433.4,7.223h-2.024l-5.119,3.688l-4.285,6.311l1.668,1.071l3.211,0.359l2.504,6.548l-1.43,2.618l-2.502,3.689l-4.644,17.147l1.785,2.856l-1.428,2.498l-10.599,7.742l-5.713-1.071l-3.215-1.191l-0.479,1.667l-4.642,18.577l-2.264,2.378l1.191,3.335l2.854,2.382l4.764-2.623l7.74,0.598l2.26-3.692l4.052-0.951l7.737,2.856l9.408,9.765v2.023l-2.024,1.429l-10.836,0.599l-3.691,2.854l-2.857-0.355l-2.022,3.214l-5.121,1.07l-3.457,5.12l-0.592,3.81l-7.379,4.763l-4.646,0.598l-5.119,6.904l-4.883,2.859l-9.408-2.025l-3.092-1.431l-3.692,3.694l-1.785,6.548l5.119,7.501l-3.335,3.451l-4.643,2.859c0,0-8.422,10.638-6.787,8.571c1.637-2.064-6.619,3.36-8.93,3.93c-2.31,0.568-14.525,1.429-14.525,1.429l-2.264-0.237l-16.906,7.144l-7.742,4.881l-2.262-1.19l-0.83-2.262l-10.36-0.597l-11.909-3.688l-3.211-3.69l-17.385-2.025l-3.217,1.43l-21.072-2.022l-0.358,3.095l1.43,4.883l-0.834,7.976l6.073,8.929l3.096,2.026l4.883-3.812h10.237l2.623,0.953l1.426,2.262l-1.19,2.5l-5.714,4.646l0.597,2.261l6.549,4.88h2.618l0.834,1.072l-0.596,2.023l4.05,3.217l9.403,1.429l4.527-1.19l5.716-5.719l6.903,0.598l2.857,4.289l-1.664,3.926l0.473,2.382l-3.688,2.263l-1.668,2.024l0.596,4.76l6.545,4.647L301.969,226.604z', + 'name': 'Neimenggu' + } + }, + 'height': 470, + 'projection': { + 'type': 'mill', + 'centralMeridian': 11.5 + }, + 'width': 600 +}); \ No newline at end of file diff --git a/src/app/panels/map/module.html b/src/app/panels/map/module.html old mode 100755 new mode 100644 index 69c249000..25832f577 --- a/src/app/panels/map/module.html +++ b/src/app/panels/map/module.html @@ -59,5 +59,7 @@ z-index: 99; } -
+
+
+
diff --git a/src/app/panels/map/module.js b/src/app/panels/map/module.js old mode 100755 new mode 100644 index 5dde7fec7..75c4ab673 --- a/src/app/panels/map/module.js +++ b/src/app/panels/map/module.js @@ -31,14 +31,7 @@ function (angular, app, _, $, worldmap) { editorTabs : [ {title:'Queries', src:'app/partials/querySelect.html'} ], - modals : [ - { - description: "Inspect", - icon: "icon-info-sign", - partial: "app/partials/inspector.html", - show: $scope.panel.spyable - } - ], + status : "Stable", description : "Displays a map of shaded regions using a field containing a 2 letter country code or US state code. Regions with more hits are shaded darker. It uses Solr faceting, so it is important that you set field values to the appropriate 2-letter codes at index time. Recent additions provide the ability to compute mean/max/min/sum of a numeric field by country or state." }; @@ -48,6 +41,7 @@ function (angular, app, _, $, worldmap) { queries : { mode : 'all', ids : [], + query : '*:*', custom : '' }, @@ -57,8 +51,11 @@ function (angular, app, _, $, worldmap) { decimal_points : 0, // The number of digits after the decimal point map : "world", useNames : false, - colors : ['#A0E2E2', '#265656'], - size : 100, + linkage_id:'a', + display:'block', + icon:"icon-caret-down", + colors : ['#fddda0', '#cd8804'], + size : 1000, exclude : [], spyable : true, index_limit : 0, @@ -90,7 +87,17 @@ function (angular, app, _, $, worldmap) { $scope.panel.decimal_points = 0; } }; + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; $scope.close_edit = function() { if ($scope.refresh) { // $scope.testMultivalued(); @@ -100,126 +107,128 @@ function (angular, app, _, $, worldmap) { }; $scope.get_data = function() { - // Make sure we have everything for the request to complete - if(dashboard.indices.length === 0) { - return; - } - $scope.panelMeta.loading = true; - delete $scope.panel.error; - - // Solr - $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); - - var request; - request = $scope.sjs.Request().indices(dashboard.indices); - - $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); - // This could probably be changed to a BoolFilter - var boolQuery = $scope.ejs.BoolQuery(); - _.each($scope.panel.queries.ids,function(id) { - boolQuery = boolQuery.should(querySrv.getEjsObj(id)); - }); - - // Then the insert into facet and make the request - request = request - .facet($scope.ejs.TermsFacet('map') - .field($scope.panel.field) - .size($scope.panel.size) - .exclude($scope.panel.exclude) - .facetFilter($scope.ejs.QueryFilter( - $scope.ejs.FilteredQuery( - boolQuery, - filterSrv.getBoolFilter(filterSrv.ids) - )))).size(0); - - $scope.populate_modal(request); - - // Build Solr query - var fq = ''; - if (filterSrv.getSolrFq()) { - fq = '&' + filterSrv.getSolrFq(); - } - var wt_json = '&wt=json'; - var rows_limit = '&rows=0'; // for map module, we don't display results from row, but we use facets. - var facet = ''; - - if ($scope.panel.mode === 'count') { - facet = '&facet=true&facet.field=' + $scope.panel.field + '&facet.limit=' + $scope.panel.size; - } else { - // if mode != 'count' then we need to use stats query - facet = '&stats=true&stats.facet=' + $scope.panel.field + '&stats.field=' + $scope.panel.stats_field; - } + if(($scope.panel.linkage_id === dashboard.current.linkage_id)||dashboard.current.enable_linkage){ + // Make sure we have everything for the request to complete + if (dashboard.indices.length === 0) { + return; + } + $scope.panelMeta.loading = true; + delete $scope.panel.error; - // Set the panel's query - $scope.panel.queries.query = querySrv.getORquery() + wt_json + fq + rows_limit + facet; + // Solr + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); - // Set the additional custom query - if ($scope.panel.queries.custom != null) { - request = request.setQuery($scope.panel.queries.query + $scope.panel.queries.custom); - } else { - request = request.setQuery($scope.panel.queries.query); - } + var request; + request = $scope.sjs.Request().indices(dashboard.indices); - var results = request.doSearch(); + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + // This could probably be changed to a BoolFilter + var boolQuery = $scope.ejs.BoolQuery(); + _.each($scope.panel.queries.ids, function (id) { + boolQuery = boolQuery.should(querySrv.getEjsObj(id)); + }); - // Populate scope when we have results - results.then(function(results) { - $scope.panelMeta.loading = false; - // Check for error and abort if found - if(!(_.isUndefined(results.error))) { - $scope.panel.error = $scope.parse_error(results.error.msg); - return; + // Then the insert into facet and make the request + request = request + .facet($scope.ejs.TermsFacet('map') + .field($scope.panel.field) + .size($scope.panel.size) + .exclude($scope.panel.exclude) + .facetFilter($scope.ejs.QueryFilter( + $scope.ejs.FilteredQuery( + boolQuery, + filterSrv.getBoolFilter(filterSrv.ids) + )))).size(0); + + $scope.populate_modal(request); + + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); } - $scope.data = {}; // empty the data for new results - var terms = []; + var wt_json = '&wt=json'; + var rows_limit = '&rows=0'; // for map module, we don't display results from row, but we use facets. + var facet = ''; - if (results.response.numFound) { - $scope.hits = results.response.numFound; + if ($scope.panel.mode === 'count') { + facet = '&facet=true&facet.field=' + $scope.panel.field + '&facet.limit=' + $scope.panel.size; } else { - // Undefined numFound or zero, clear the map. - $scope.$emit('render'); - return false; + // if mode != 'count' then we need to use stats query + facet = '&stats=true&stats.facet=' + $scope.panel.field + '&stats.field=' + $scope.panel.stats_field; } - if ($scope.panel.mode === 'count') { - terms = results.facet_counts.facet_fields[$scope.panel.field]; - } else { // stats mode - _.each(results.stats.stats_fields[$scope.panel.stats_field].facets[$scope.panel.field], function(stats_obj,facet_field) { - terms.push(facet_field, stats_obj[$scope.panel.mode]); - }); + // Set the panel's query + $scope.panel.queries.query = querySrv.getORquery() + wt_json + fq + rows_limit + facet; + + // Set the additional custom query + if ($scope.panel.queries.custom != null) { + request = request.setQuery($scope.panel.queries.query + $scope.panel.queries.custom); + } else { + request = request.setQuery($scope.panel.queries.query); } - if ($scope.hits > 0) { - for (var i=0; i < terms.length; i += 2) { - // Skip states with zero count to make them greyed out in the map. - if (terms[i+1] > 0) { - // if $scope.data[terms] is undefined, assign the value to it - // otherwise, we will add the value. This case can happen when - // the data contains both uppercase and lowercase state letters with - // duplicate states (e.g. CA and ca). By adding the value, the map will - // show correct counts for states with mixed-case letters. - if(($scope.panel.map === 'world' || $scope.panel.map === 'world-antarctica') && $scope.panel.useNames) { - if(worldmap.countryCodes[terms[i]]) { - if (!$scope.data[worldmap.countryCodes[terms[i]]]) { - $scope.data[worldmap.countryCodes[terms[i]]] = terms[i+1]; - } else { - $scope.data[worldmap.countryCodes[terms[i]]] += terms[i+1]; - } - } - } - else { - if (!$scope.data[terms[i].toUpperCase()]) { - $scope.data[terms[i].toUpperCase()] = terms[i+1]; - } else { - $scope.data[terms[i].toUpperCase()] += terms[i+1]; - } - } + var results = request.doSearch(); + + // Populate scope when we have results + results.then(function (results) { + $scope.panelMeta.loading = false; + // Check for error and abort if found + if (!(_.isUndefined(results.error))) { + $scope.panel.error = $scope.parse_error(results.error.msg); + return; + } + $scope.data = {}; // empty the data for new results + var terms = []; + + if (results.response.numFound) { + $scope.hits = results.response.numFound; + } else { + // Undefined numFound or zero, clear the map. + $scope.$emit('render'); + return false; } - } - } - $scope.$emit('render'); - }); + if ($scope.panel.mode === 'count') { + terms = results.facet_counts.facet_fields[$scope.panel.field]; + } else { // stats mode + _.each(results.stats.stats_fields[$scope.panel.stats_field].facets[$scope.panel.field], function (stats_obj, facet_field) { + terms.push(facet_field, stats_obj[$scope.panel.mode]); + }); + } + + if ($scope.hits > 0) { + for (var i = 0; i < terms.length; i += 2) { + // Skip states with zero count to make them greyed out in the map. + if (terms[i + 1] > 0) { + // if $scope.data[terms] is undefined, assign the value to it + // otherwise, we will add the value. This case can happen when + // the data contains both uppercase and lowercase state letters with + // duplicate states (e.g. CA and ca). By adding the value, the map will + // show correct counts for states with mixed-case letters. + if (($scope.panel.map === 'world' || $scope.panel.map === 'world-antarctica') && $scope.panel.useNames) { + if (worldmap.countryCodes[terms[i]]) { + if (!$scope.data[worldmap.countryCodes[terms[i]]]) { + $scope.data[worldmap.countryCodes[terms[i]]] = terms[i + 1]; + } else { + $scope.data[worldmap.countryCodes[terms[i]]] += terms[i + 1]; + } + } + } + else { + if (!$scope.data[terms[i].toUpperCase()]) { + $scope.data[terms[i].toUpperCase()] = terms[i + 1]; + } else { + $scope.data[terms[i].toUpperCase()] += terms[i + 1]; + } + } + } + } + } + + $scope.$emit('render'); + }); + } }; // I really don't like this function, too much dom manip. Break out into directive? @@ -228,19 +237,26 @@ function (angular, app, _, $, worldmap) { }; $scope.build_search = function(field,value) { - // Set querystring to both uppercase and lowercase state values with double-quote around the value - // to prevent query error from state=OR (Oregon). - // When using Country Name option, the country name is supposed to be in capitalized format. But we - // will also add queries for searching both uppercase and lowercase (e.g. Thailand OR THAILAND OR thailand). - if (!$scope.panel.useNames) { - filterSrv.set({type:'querystring',mandate:'must',query:field+':"'+value.toUpperCase()+ - '" OR '+field+':"'+value.toLowerCase()+'"'}); - } else { - filterSrv.set({type:'querystring',mandate:'must',query:field+':"'+value.toUpperCase()+ - '" OR '+field+':"'+value.toLowerCase()+'" OR '+field+':"'+value+'"'}); - } - - dashboard.refresh(); + + // Set querystring to both uppercase and lowercase state values with double-quote around the value + // to prevent query error from state=OR (Oregon). + // When using Country Name option, the country name is supposed to be in capitalized format. But we + // will also add queries for searching both uppercase and lowercase (e.g. Thailand OR THAILAND OR thailand). + if (!$scope.panel.useNames) { + filterSrv.set({ + type: 'querystring', mandate: 'must', query: field + ':"' + value.toUpperCase() + + '" OR ' + field + ':"' + value.toLowerCase() + '"' + }); + } else { + filterSrv.set({ + type: 'querystring', mandate: 'must', query: field + ':"' + value.toUpperCase() + + '" OR ' + field + ':"' + value.toLowerCase() + '" OR ' + field + ':"' + value + '"' + }); + } + dashboard.current.linkage_id = $scope.panel.linkage_id; + dashboard.current.enable_linkage = false; + dashboard.refresh(); + }; }); @@ -269,7 +285,7 @@ function (angular, app, _, $, worldmap) { series: { regions: [{ values: scope.data, - scale: scope.panel.colors, + scale: ['#C8EEFF', '#0071A4'], normalizeFunction: 'polynomial' }] }, diff --git a/src/app/panels/multiseries/module.js b/src/app/panels/multiseries/module.js deleted file mode 100644 index 632129469..000000000 --- a/src/app/panels/multiseries/module.js +++ /dev/null @@ -1,494 +0,0 @@ -/* - - ## Multiseries Panel - -*/ -define([ - 'angular', - 'app', - 'underscore', - 'jquery', - 'd3' -], function(angular, app, _, $, d3) { - 'use strict'; - - var module = angular.module('kibana.panels.multiseries', []); - app.useModule(module); - - module.controller('multiseries', function($scope, $timeout, timer, dashboard, querySrv, filterSrv) { - $scope.panelMeta = { - modals: [{ - description: "Inspect", - icon: "icon-info-sign", - partial: "app/partials/inspector.html", - show: $scope.panel.spyable - }], - editorTabs: [{ - title: 'Queries', - src: 'app/partials/querySelect.html' - }], - status: "Experimental", - description: "Multiseries chart panel currently support only plotting data of the same field type. You have to define which fields to be plotted on Y-axis fields. Data must have X-axis as timestamp and Y-axis must have values, if not it will be discarded." - }; - - // default values - var _d = { - queries: { - mode: 'all', - ids: [], - query: '*:*', - custom: '' - }, - size: 1000, - max_rows: 10000, // maximum number of rows returned from Solr - field: 'timestamp', - yAxis: '', - right_yAxis: '', - fl: '', - right_fl: '', - spyable: true, - show_queries: true, - interpolate: 'basis', - right_interpolate: 'basis', - rightYEnabled: false, - showLegend: true, - showRightLegend: true, - refresh: { - enable: false, - interval: 2 - } - }; - - _.defaults($scope.panel, _d); - - $scope.init = function() { - // Start refresh timer if enabled - if ($scope.panel.refresh.enable) { - $scope.set_timer($scope.panel.refresh.interval); - } - - $scope.$on('refresh', function() { - $scope.get_data(); - }); - $scope.get_data(); - }; - - $scope.set_timer = function(refresh_interval) { - $scope.panel.refresh.interval = refresh_interval; - if (_.isNumber($scope.panel.refresh.interval)) { - timer.cancel($scope.refresh_timer); - $scope.realtime(); - } else { - timer.cancel($scope.refresh_timer); - } - }; - - $scope.realtime = function() { - if ($scope.panel.refresh.enable) { - timer.cancel($scope.refresh_timer); - - $scope.refresh_timer = timer.register($timeout(function() { - $scope.realtime(); - $scope.get_data(); - }, $scope.panel.refresh.interval*1000)); - } else { - timer.cancel($scope.refresh_timer); - } - }; - - $scope.get_data = function() { - // Show progress by displaying a spinning wheel icon on panel - delete $scope.panel.error; - $scope.panelMeta.loading = true; - - // Set Solr server - $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); - - // Construct Solr query - var request = $scope.sjs.Request(); - var fq = ''; - if (filterSrv.getSolrFq()) { - fq = '&' + filterSrv.getSolrFq(); - } - var wt_json = '&wt=json'; - // NOTE: $scope.panel.field is the time field for x-Axis - // TODO: need to rename to $scope.panel.timefield - var fl = '&fl=' + $scope.panel.field + ',' + $scope.panel.fl; - if ($scope.panel.right_fl) { - fl += ',' + $scope.panel.right_fl; - } - var rows_limit = '&rows=' + $scope.panel.max_rows; - var sort = '&sort=' + $scope.panel.field + ' asc'; - - $scope.panel.queries.query = querySrv.getORquery() + fq + fl + wt_json + rows_limit + sort; - - // Set the additional custom query - if ($scope.panel.queries.custom != null) { - request = request.setQuery($scope.panel.queries.query + $scope.panel.queries.custom); - } else { - request = request.setQuery($scope.panel.queries.query); - } - - // Execute the search and get results - var results = request.doSearch(); - - // Populate scope when we have results - results.then(function (results) { - if(!(_.isUndefined(results.error))) { - $scope.panel.error = $scope.parse_error(results.error.msg); - return; - } - // build $scope.data array - $scope.panelMeta.loading = false; - $scope.data = []; - - if (!(_.isUndefined(results.error))) { - $scope.panel.error = $scope.parse_error(results.error.msg); - $scope.render(); - return; - } - - $scope.data = results.response.docs; - $scope.render(); - }); - - // Hide the spinning wheel icon - $scope.panelMeta.loading = false; - }; - - $scope.set_refresh = function(state) { - $scope.refresh = state; - }; - - $scope.close_edit = function() { - // Start refresh timer if enabled - if ($scope.panel.refresh.enable) { - $scope.set_timer($scope.panel.refresh.interval); - } - if ($scope.refresh) { - $scope.get_data(); - } - $scope.refresh = false; - $scope.$emit('render'); - }; - - $scope.render = function() { - $scope.$emit('render'); - }; - - $scope.populate_modal = function(request) { - $scope.inspector = angular.toJson(JSON.parse(request.toString()), true); - }; - - $scope.pad = function(n) { - return (n < 10 ? '0' : '') + n; - }; - }); - - module.directive('multiseriesChart', function() { - return { - restrict: 'E', - link: function(scope, element) { - - scope.$on('render', function() { - render_panel(); - }); - - angular.element(window).bind('resize', function() { - render_panel(); - }); - - // Function for rendering panel - function render_panel() { - - element.html(""); - - var el = element[0]; - // deepcopy of the data in the scope - var data; - data = jQuery.extend(true, [], scope.data); // jshint ignore: line - - if (d3.keys(data[0]).indexOf(scope.panel.field) === -1) { - return; - } - - var parent_width = $("#multiseries").width(), - parent_height = $('#multiseries').parent().parent().parent().parent().height(); - - var margin = { - top: 20, - right: 80, - bottom: 30, - left: 50 - }, - width = parent_width - margin.left - margin.right - 50, - height = parent_height - margin.top - margin.bottom; - - // The need for two date parsers is that sometimes solr removes the .%L part if it equals 000 - // So double checking to make proper parsing format and cause no error - var parseDate = d3.time.format.utc("%Y-%m-%dT%H:%M:%S.%LZ"); - var parseDate2 = d3.time.format.utc("%Y-%m-%dT%H:%M:%SZ"); - - var isDate = false; - // Check if x is date or another type - if (data && data.length > 0) { - var sample_date = data[0][scope.panel.field]; - isDate = parseDate.parse(String(sample_date)) || parseDate2.parse(String(sample_date)); - } - - // d3 stuffs - var x; - if (isDate) { - x = d3.time.scale().range([0, width]); - } else { - x = d3.scale.linear().range([0, width]); - } - - var y = d3.scale.linear().range([height, 0]); - - var color = d3.scale.category10(); - var xAxis = d3.svg.axis().scale(x).orient("bottom"); - var yAxis = d3.svg.axis().scale(y).orient("left"); - - var line = d3.svg.line() - .interpolate(scope.panel.interpolate) // interpolate option - .x(function(d) { - return x(d.xValue); - }) - .y(function(d) { - return y(d.yValue); - }); - - // Colors domain must be the same count of fl - var fl = scope.panel.fl.split(','); - color.domain(d3.keys(data[0]).filter(function(key) { - return (fl.indexOf(key) !== -1); - })); - - var y_right,y_right_color,yAxis_right,line_right; - - if(scope.panel.rightYEnabled) { - y_right = d3.scale.linear().range([height, 0]); - y_right_color = d3.scale.category20b(); - yAxis_right = d3.svg.axis().scale(y_right).orient("right"); - line_right = d3.svg.line() - .interpolate(scope.panel.right_interpolate) - .x(function(d) { return x(d.xValue); }) - .y(function(d) { return y_right(d.yValue); }); - var rightAxisList = scope.panel.right_fl.split(','); - y_right_color.domain(d3.keys(data[0]).filter(function(key){ - return (rightAxisList.indexOf(key) !== -1); - })); - } - - if (isDate) { - // That in case x-axis was date, what if not? - data.forEach(function(d) { - var newDate = parseDate.parse(String(d[scope.panel.field])); - d[scope.panel.field] = newDate !== null ? newDate : parseDate2.parse(String(d[scope.panel.field])); - }); - } - - var yFields = color.domain().map(function(name) { - return { - name: name, - values: data.map(function(d) { - return { - xValue: d[scope.panel.field], - yValue: +d[name] - }; - }) - }; - }); - - // remove NaN values and let d3 to perform the interpolation - yFields.forEach(function(c) { - c.values = c.values.filter(function(d) { - return !isNaN(d.yValue); - }); - }); - - x.domain(d3.extent(data, function(d) { - return d[scope.panel.field]; - })); - - y.domain([ - d3.min(yFields, function(c) { - return d3.min(c.values, function(v) { - return v.yValue; - }); - }), - d3.max(yFields, function(c) { - return d3.max(c.values, function(v) { - return v.yValue; - }); - }) - ]); - - var yFields_right; - if(scope.panel.rightYEnabled) { - yFields_right = y_right_color.domain().map(function(name) { - return { - name: name, - values: data.map(function(d) { - return {xValue: d[scope.panel.field], yValue: +d[name]}; - }) - }; - }); - - y_right.domain([ - d3.min(yFields_right, function(c) { return d3.min(c.values, function(v) { return v.yValue; }); }), - d3.max(yFields_right, function(c) { return d3.max(c.values, function(v) { return v.yValue; }); }) - ]); - } - - // function zoomed() { - // svg.select(".x.axis").call(xAxis); - // svg.select(".y.axis").call(yAxis); - // svg.selectAll('.yfield path.line').data(yFields).attr('d', function(d) { - // return line(d.values); - // }); - // if(scope.panel.rightYEnabled) { - // svg.selectAll('.yfield_right path.line').data(yFields_right).attr('d', function(d) { - // return line_right(d.values); - // }); - // } - // } - // // zoom functionality is disabled - // var zoom = d3.behavior.zoom() - // .x(x) - // .y(y) - // .scaleExtent([1, 5]) - // .on("zoom", zoomed); - - var svg = d3.select(el).append("svg") - .attr("width", width + margin.left + margin.right) - .attr("height", height + margin.top + margin.bottom) - .attr("viewBox", "0 0 " + parent_width + " " + parent_height) - .attr("preserveAspectRatio", "xMidYMid") - .append("g") - .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); - - svg.append("g") - .attr("class", "x axis") - .attr("transform", "translate(0," + height + ")") - .call(xAxis); - - svg.append("g") - .attr("class", "y axis") - .call(yAxis) - .append("text") - .attr("transform", "rotate(-90)") - .attr("y", 6) - .attr("dy", ".71em") - .style("text-anchor", "end") - .text(scope.panel.yAxis); - - var yfield = svg.selectAll(".yfield") - .data(yFields) - .enter().append("g") - .attr("class", "yfield"); - - yfield.append("path") - .attr("class", "line") - .attr("d", function(d) { - return line(d.values); - }) - .style("stroke", function(d) { - return color(d.name); - }) - .style("fill", "transparent"); - - var yfield_right; - if(scope.panel.rightYEnabled) { - svg.append("g") - .attr("class", "y axis") - .attr("transform", "translate(" + width + " ,0)") - .style("fill", "blue") - .call(yAxis_right) - .append("text") - .attr("transform", "rotate(-90)") - .attr("y", 6) - .attr("dy", "-1.2em") - .style("text-anchor", "end") - .text(scope.panel.right_yAxis); // TODO: make it defined in panel - - yfield_right = svg.selectAll(".yfield_right") - .data(yFields_right) - .enter().append("g") - .attr("class", "yfield_right"); - - yfield_right.append("path") - .attr("class", "line") - .attr("d", function(d) { return line_right(d.values); }) - .style("stroke", function(d) { return y_right_color(d.name); }) - .style("fill", "transparent"); - } - - if(scope.panel.showLegend) { - var legend = svg.append("g") - .attr("class", "legend") - .attr("height", 100) - .attr("width", 150) - .attr('transform', 'translate(30,40)'); - - legend.selectAll('rect') - .data(yFields) - .enter() - .append("rect") - .attr("x", width + 50) - .attr("y", function(d, i){ return i * 20;}) - .attr("width", 10) - .attr("height", 10) - .style("fill", function(d) { - return color(d.name); - }); - - legend.selectAll('text') - .data(yFields) - .enter() - .append("text") - .attr("x", width + 65) - .attr("y", function(d, i){ return i * 20 + 9;}) - .text(function(d) { - return d.name; - }); - } - - // Another Legend - if(scope.panel.rightYEnabled && scope.panel.showRightLegend) { - var legend_right = svg.append("g") - .attr("class", "legend") - .attr("height", 100) - .attr("width", 150) - .attr('transform', 'translate(30,150)'); - - legend_right.selectAll('rect') - .data(yFields_right) - .enter() - .append("rect") - .attr("x", width + 50) - .attr("y", function(d, i){ return i * 20;}) - .attr("width", 10) - .attr("height", 10) - .style("fill", function(d) { - return y_right_color(d.name); - }); - - legend_right.selectAll('text') - .data(yFields_right) - .enter() - .append("text") - .attr("x", width + 65) - .attr("y", function(d, i){ return i * 20 + 9;}) - .text(function(d) { - return d.name; - }); - } - } - - render_panel(); - } - }; - }); -}); \ No newline at end of file diff --git a/src/app/panels/pies/editor.html b/src/app/panels/pies/editor.html new file mode 100644 index 000000000..8fb70f337 --- /dev/null +++ b/src/app/panels/pies/editor.html @@ -0,0 +1,121 @@ +
+
+ + +
+
+ + +
+
+ + +
+
+ + + +
+
+ + +
+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+
+
Real-time (Auto-refresh)
+
+ +
+
+ + +
+
+
+
Linkage Effective
+
+ +
+ +
diff --git a/src/app/panels/pies/module.html b/src/app/panels/pies/module.html new file mode 100644 index 000000000..3024c79c6 --- /dev/null +++ b/src/app/panels/pies/module.html @@ -0,0 +1,55 @@ +
+ + + + + +
+ + + + + + + + +
+
\ No newline at end of file diff --git a/src/app/panels/pies/module.js b/src/app/panels/pies/module.js new file mode 100644 index 000000000..071efd7c4 --- /dev/null +++ b/src/app/panels/pies/module.js @@ -0,0 +1,1532 @@ +/* + ## pies + + ### Parameters + * style :: A hash of css styles + * size :: top N + * arrangement :: How should I arrange the query results? 'horizontal' or 'vertical' + * chart :: Show a chart? 'none', 'bar', 'pie' + * donut :: Only applies to 'pie' charts. Punches a hole in the chart for some reason + * tilt :: Only 'pie' charts. Janky 3D effect. Looks terrible 90% of the time. + * lables :: Only 'pie' charts. Labels on the pie? +*/ +define([ + 'angular', + 'app', + 'underscore', + 'jquery', + 'kbn', + 'echarts-liquidfill', +], +function (angular, app, _, $, kbn) { + 'use strict'; + + var module = angular.module('kibana.panels.pies', []); + app.useModule(module); + + module.controller('pies', function($scope, $timeout, timer, querySrv, dashboard, filterSrv) { + $scope.panelMeta = { + exportfile: true, + editorTabs : [ + {title:'Queries', src:'app/partials/querySelect.html'} + ], + status : "Stable", + description : "Displays the results of a Solr facet as a pie chart, bar chart, or a table. Newly added functionality displays min/max/mean/sum of a stats field, faceted by the Solr facet field, again as a pie chart, bar chart or a table." + }; + + // Set and populate defaults + var _d = { + queries : { + mode : 'all', + ids : [], + query : '*:*', + custom : '' + }, + mode : 'count', // mode to tell which number will be used to plot the chart. + field : '', + stats_field : '', + decimal_points : 0, // The number of digits after the decimal point + exclude : [], + missing : false, + other : false, + size : 10000, + sortBy : 'count', + order : 'descending', + fontsize : 12, + donut : false, + tilt : false, + display:'block', + + icon:"icon-caret-down", + labels : true, + ylabels :true, + logAxis : false, + arrangement : 'vertical', + RoseType : 'area', + chart : 'pie', + solrFq :filterSrv.getSolrFq(), + exportSize : 10000, + linkage_id:'a', + value_sort:'rs_timestamp', + defaulttimestamp:true, + lastColor : '', + spyable : true, + show_queries:true, + error : '', + chartColors : querySrv.colors, + refresh: { + enable: false, + interval: 2 + } + }; + _.defaults($scope.panel,_d); + + $scope.init = function () { + $scope.hits = 0; + //$scope.testMultivalued(); + + // Start refresh timer if enabled + if ($scope.panel.refresh.enable) { + $scope.set_timer($scope.panel.refresh.interval); + } + + $scope.$on('refresh',function(){ + $scope.get_data(); + }); + + $scope.get_data(); + }; + + $scope.testMultivalued = function() { + if($scope.panel.field && $scope.fields.typeList[$scope.panel.field] && $scope.fields.typeList[$scope.panel.field].schema.indexOf("M") > -1) { + $scope.panel.error = "Can't proceed with Multivalued field"; + return; + } + + if($scope.panel.stats_field && $scope.fields.typeList[$scope.panel.stats_field].schema.indexOf("M") > -1) { + $scope.panel.error = "Can't proceed with Multivalued field"; + return; + } + }; + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; + /** + * + * + * @param {String} filetype -'json', 'xml', 'csv' + */ + $scope.build_query = function(filetype, isForExport) { + + // Build Solr query + var fq = ''; + + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + if(!$scope.panel.defaulttimestamp){ + fq = fq.replace(filterSrv.getTimeField(),$scope.panel.value_sort); + } + } + var wt_json = '&wt=' + filetype; + var rows_limit = isForExport ? '&rows=0' : ''; // for pies, we do not need the actual response doc, so set rows=0 + var facet = ''; + + if ($scope.panel.mode === 'count') { + facet = '&facet=true&facet.field=' + $scope.panel.field + '&facet.limit=' + $scope.panel.size + '&facet.missing=true'; + } else { + // if mode != 'count' then we need to use stats query + // stats does not support something like facet.limit, so we have to sort and limit the results manually. + facet = '&stats=true&stats.facet=' + $scope.panel.field + '&stats.field=' + $scope.panel.stats_field + '&facet.missing=true'; + } + facet += '&f.' + $scope.panel.field + '.facet.sort=' + ($scope.panel.sortBy || 'count'); + + var exclude_length = $scope.panel.exclude.length; + var exclude_filter = ''; + if(exclude_length > 0){ + for (var i = 0; i < exclude_length; i++) { + if($scope.panel.exclude[i] !== "") { + exclude_filter += '&fq=-' + $scope.panel.field +":"+ $scope.panel.exclude[i]; + } + } + } + + return querySrv.getORquery() + wt_json + rows_limit + fq + exclude_filter + facet + ($scope.panel.queries.custom != null ? $scope.panel.queries.custom : ''); + }; + + $scope.exportfile = function(filetype) { + + var query = this.build_query(filetype, true); + + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + var request = $scope.sjs.Request().indices(dashboard.indices), + response; + + request.setQuery(query); + + response = request.doSearch(); + + // Populate scope when we have results + response.then(function(response) { + kbn.download_response(response, filetype, "pies"); + }); + }; + + $scope.set_timer = function(refresh_interval) { + $scope.panel.refresh.interval = refresh_interval; + if (_.isNumber($scope.panel.refresh.interval)) { + timer.cancel($scope.refresh_timer); + $scope.realtime(); + } else { + timer.cancel($scope.refresh_timer); + } + }; + + $scope.realtime = function() { + if ($scope.panel.refresh.enable) { + timer.cancel($scope.refresh_timer); + + $scope.refresh_timer = timer.register($timeout(function() { + $scope.realtime(); + $scope.get_data(); + }, $scope.panel.refresh.interval*1000)); + } else { + timer.cancel($scope.refresh_timer); + } + }; + + $scope.get_data = function() { + if(($scope.panel.linkage_id === dashboard.current.linkage_id)||dashboard.current.enable_linkage){ + // Make sure we have everything for the request to complete + if (dashboard.indices.length === 0) { + return; + } + + delete $scope.panel.error; + $scope.panelMeta.loading = true; + var request, results; + + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + request = $scope.sjs.Request().indices(dashboard.indices); + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + + // Populate the inspector panel + $scope.inspector = angular.toJson(JSON.parse(request.toString()), true); + + var query = this.build_query('json', false); + + // Set the panel's query + $scope.panel.queries.query = query; + + request.setQuery(query); + + results = request.doSearch(); + + // Populate scope when we have results + results.then(function (results) { + // Check for error and abort if found + if (!(_.isUndefined(results.error))) { + $scope.panel.error = $scope.parse_error(results.error.msg); + $scope.data = []; + $scope.label = []; + $scope.panelMeta.loading = false; + $scope.$emit('render'); + return; + } + + // Function for validating HTML color by assign it to a dummy
+ // and let the browser do the work of validation. + /*var isValidHTMLColor = function (color) { + // clear attr first, before comparison + $('#colorTest').removeAttr('style'); + var valid = $('#colorTest').css('color'); + $('#colorTest').css('color', color); + + if (valid === $('#colorTest').css('color')) { + return false; + } else { + return true; + } + };*/ + + // Function for customizing chart color by using field values as colors. + /* + var addSliceColor = function (slice, color) { + if ($scope.panel.useColorFromField && isValidHTMLColor(color)) { + slice.color = color; + } + return slice; + }; + */ + + var sum = 0; + var k = 0; + var missing = 0; + $scope.panelMeta.loading = false; + $scope.hits = results.response.numFound; + $scope.data = []; + $scope.label = []; + $scope.radardata = []; + $scope.maxdata = 0; + + + if ($scope.panel.mode === 'count') { + // In count mode, the y-axis min should be zero because count value cannot be negative. + $scope.yaxis_min = 0; + + _.each(results.facet_counts.facet_fields, function (v) { + for (var i = 0; i < v.length; i++) { + var term = v[i]; + i++; + var count = v[i]; + + sum += count; + if (term === null) { + missing = count; + } else { + if ($scope.maxdata < count) { + $scope.maxdata = count; + } + // if count = 0, do not add it to the chart, just skip it + if (count === 0) { + continue; + } + term = term.replace(/[\r\n]/g, ""); + + var slice = {value: count, name: term}; + $scope.label.push(term); + $scope.data.push(slice); + $scope.radardata.push(count); + } + } + }); + } else { + // In stats mode, set y-axis min to null so jquery.flot will set the scale automatically. + $scope.yaxis_min = null; + _.each(results.stats.stats_fields[$scope.panel.stats_field].facets[$scope.panel.field], function (stats_obj, facet_field) { + var slice = {label: facet_field, data: [[k, stats_obj[$scope.panel.mode]]], actions: true}; + $scope.data.push(slice); + }); + } + // Sort the results + $scope.data = _.sortBy($scope.data, function (d) { + return $scope.panel.sortBy === 'index' ? d.name : d.value; + }); + if ($scope.panel.order === 'descending') { + $scope.data.reverse(); + $scope.label.reverse(); + $scope.radardata.reverse(); + } + + // Slice it according to panel.size, and then set the x-axis values with k. + // $scope.data = $scope.data.slice(0,$scope.panel.size); + //_.each($scope.data, function(v) { + // v.data[0][0] = k; + // k++; + // }); + + if ($scope.panel.field && $scope.fields.typeList[$scope.panel.field] && $scope.fields.typeList[$scope.panel.field].schema.indexOf("T") > -1) { + $scope.hits = sum; + } + + // $scope.data.push({label:'Missing field', + // data:[[k,results.facets.pies.missing]],meta:"missing",color:'#aaa',opacity:0}); + // TODO: Hard coded to 0 for now. Solr faceting does not provide 'missing' value. + //data:[[k,missing]],meta:"missing",color:'#aaa',opacity:0}); + // $scope.data.push({label:'Other values', + // data:[[k+1,results.facets.pies.other]],meta:"other",color:'#444'}); + // TODO: Hard coded to 0 for now. Solr faceting does not provide 'other' value. + // data:[[k+1,$scope.hits-sum]],meta:"other",color:'#444'}); + + $scope.$emit('render'); + }); + } + }; + + $scope.build_search = function(term,negate) { + if (_.isUndefined(term.meta)) { + filterSrv.set({ + type: 'terms', field: $scope.panel.field, value: term.name, + mandate: (negate ? 'mustNot' : 'must') + }); + } else if (term.meta === 'missing') { + filterSrv.set({ + type: 'exists', field: $scope.panel.field, + mandate: (negate ? 'must' : 'mustNot') + }); + } else { + return; + } + dashboard.current.linkage_id = $scope.panel.linkage_id; + dashboard.current.enable_linkage = false; + dashboard.refresh(); + + }; + + $scope.set_refresh = function (state) { + $scope.refresh = state; + // if 'count' mode is selected, set decimal_points to zero automatically. + if ($scope.panel.mode === 'count') { + $scope.panel.decimal_points = 0; + } + }; + + $scope.close_edit = function() { + // Start refresh timer if enabled + if ($scope.panel.refresh.enable) { + $scope.set_timer($scope.panel.refresh.interval); + } + + if ($scope.refresh) { + // $scope.testMultivalued(); + $scope.get_data(); + } + $scope.refresh = false; + $scope.$emit('render'); + }; + + $scope.showMeta = function(term) { + if(_.isUndefined(term.meta)) { + return true; + } + if(term.meta === 'other' && !$scope.panel.other) { + return false; + } + if(term.meta === 'missing' && !$scope.panel.missing) { + return false; + } + return true; + }; + + }); + + module.directive('piesChart', function(querySrv,dashboard,filterSrv) { + return { + restrict: 'A', + link: function(scope, elem) { + var myChart; + // Receive render events + scope.$on('render',function(){ + render_panel(); + }); + + // Re-render if the window is resized + angular.element(window).bind('resize', function(){ + render_panel(); + }); + + // Function for rendering panel + function render_panel() { + var colors = []; + + // IE doesn't work without this + elem.css({height:scope.panel.height||scope.row.height}); + + // Make a clone we can operate on. + + + + if (filterSrv.idsByTypeAndField('pies',scope.panel.field).length > 0) { + colors.push(scope.panel.lastColor); + } else { + colors = scope.panel.chartColors; + } + + var option_nodata = { + series: [{ + + type: 'wordCloud', + //size: ['9%', '99%'], + sizeRange: [50, 50], + //textRotation: [0, 45, 90, -45], + rotationRange: [0, 0], + //shape: 'circle', + textPadding: 0, + autoSize: { + enable: true, + minSize: 6 + }, + textStyle: { + normal: { + color: '#1a93f9' + }, + emphasis: { + shadowBlur: 10, + shadowColor: '#333' + } + }, + data: [{ + name: "NO DATA", + value: 1 + }] + }] +}; + + + var idd = scope.$id; + var labelcolor = false; + if (dashboard.current.style === 'dark'){ + labelcolor = true; + } + // Add plot to scope so we can build out own legend + var echarts = require('echarts'); + if(myChart) { + myChart.dispose(); + } + + if(scope.panel.chart === 'dashboard') { + + var AP_1 = 0.0; + var AP_2 = 0.0; + var AP_n = 0.0; + for (var i = 0; i < scope.data.length; i++) { + AP_n = AP_n+scope.data[i].value; + if(parseInt(scope.data[i].name)<=scope.panel.threshold_first ){ + AP_1+=scope.data[i].value; + }else if(parseInt(scope.data[i].name)scope.panel.threshold_first){ + AP_2+=scope.data[i].value*0.5; + } + } + var APdex =100; + if(AP_n !== 0){ + APdex = parseInt(100*(AP_1+AP_2)/AP_n); + //APdex = (AP_1+AP_2)/AP_n; + } + + myChart = echarts.init(document.getElementById(idd)); + + var option = { + + + toolbox: { + show : false, + feature : { + mark : {show: false}, + restore : {show: false}, + saveAsImage : {show: false} + } + }, + grid: { + left: '0%', + right: '0%', + bottom: '0%', + top: 90 + }, + series : [ + { + name:'Health', + + type:'gauge', + min:scope.panel.dashboard_max, + max:scope.panel.dashboard_min, + splitNumber:scope.panel.dashboard_splitNumber, + radius: '96%', + axisLine: { // åæ ‡è½´çº¿ + lineStyle: { // 属性lineStyleæŽ§åˆ¶çº¿æ¡æ ·å¼ + color: [[0.6, colors[0]],[0.82, colors[1]],[1, colors[2]]],//'#1e90ff''#F6AB60''#EB5768' + width: 5, + shadowColor : labelcolor?'#ddfdfa':colors[7], //é»˜è®¤é€æ˜Ž + shadowBlur: 40 + } + }, + axisLabel: { // åæ ‡è½´å°æ ‡è®° + textStyle: { // 属性lineStyleæŽ§åˆ¶çº¿æ¡æ ·å¼ + fontWeight: 'bolder', + color: labelcolor?'#fff':'#696969', + shadowColor : labelcolor?'#fff':colors[7], //é»˜è®¤é€æ˜Ž + shadowBlur: 40, + fontStyle: 'italic', + fontSize:scope.panel.fontsize + } + }, + axisTick: { // åæ ‡è½´å°æ ‡è®° + length :18, // 属性length控制线长 + lineStyle: { // 属性lineStyleæŽ§åˆ¶çº¿æ¡æ ·å¼ + color: 'auto', + shadowColor : labelcolor?'#fff':colors[7], //é»˜è®¤é€æ˜Ž + shadowBlur: 40 + } + }, + splitLine: { // 分隔线 + length :28, // 属性length控制线长 + lineStyle: { // 属性lineStyle(详è§lineStyleï¼‰æŽ§åˆ¶çº¿æ¡æ ·å¼ + width:4, + color: labelcolor?'#fff':colors[8], + shadowColor : labelcolor?'#fff':colors[7], //é»˜è®¤é€æ˜Ž + shadowBlur: 40 + } + }, + pointer: { // 指针 + length:'90%', + width:3 + }, + itemStyle:{ + normal:{ + color:labelcolor?'#fff':colors[6], + shadowColor: colors[7], + shadowBlur: 30, + borderWidth:2, + borderColor: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, color: colors[4] // 0% 处的颜色 + }, { + offset: 0.7, color: colors[5] // 70% 处的颜色 + },{ + offset: 1, color: '#fff' // 100% 处的颜色 + }], false) + }, + emphasis:{ + color:labelcolor?'#fff':'#696969', + shadowColor: colors[3], + shadowBlur: 30, + borderWidth:2, + borderColor: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, color: 'red' // 0% 处的颜色 + }, { + offset: 0.7, color: '#50d1f1' // 100% 处的颜色 + },{ + offset: 1, color: '#fff' // 100% 处的颜色 + }], false) + + } + }, + title : { + textStyle: { // 其余属性默认使用全局文本样å¼ï¼Œè¯¦è§TEXTSTYLE + fontWeight: 'bolder', + fontSize: scope.panel.fontsize+18, + fontStyle: 'italic', + color: labelcolor?'#fff':'#696969', + shadowColor :labelcolor?'#fff':'#696969', //é»˜è®¤é€æ˜Ž + shadowBlur: 40 + } + }, + detail : { + formatter:'{value}%', + // x, y,å•ä½px + textStyle: { // 其余属性默认使用全局文本样å¼ï¼Œè¯¦è§TEXTSTYLE + fontWeight: 'bolder', + color: labelcolor?'#fff':'#696969', + fontSize:scope.panel.fontsize+10 + } + }, + data:[{value: APdex, name: scope.panel.title}] + } + + ] + }; + // 使用刚指定的é…ç½®é¡¹å’Œæ•°æ®æ˜¾ç¤ºå›¾è¡¨ã€‚ + myChart.setOption(option); + + } + + if(scope.panel.chart === 'pie') { + + myChart = echarts.init(document.getElementById(idd)); + + + var option1 = { + title : { + show:false, + x:'center' + }, + color:colors, + tooltip : { + trigger: 'item', + confine:true, + formatter: "{a}
{b} : {c} ({d}%)" + }, + legend: { + show:scope.panel.eLegend, + orient: scope.panel.arrangement, + left: 'left', + top:'1%', + bottom:'1%', + + textStyle:{ + fontSize:scope.panel.fontsize, + color:'auto' + }, + + data: scope.data + }, + series : [ + { + name:scope.panel.title, + type: 'pie', + + radius : scope.panel.donut ?['60%','90%']:'90%', + label :{ + normal:{ + show:scope.panel.donut ? false:scope.panel.labels, + position:scope.panel.donut ?'center':'inside', + textStyle:{ + fontSize:scope.panel.fontsize + } + }, + emphasis: { + show: scope.panel.donut, + textStyle: { + fontSize: scope.panel.fontsize, + fontWeight: 'bold' + } + } + + }, + center: ['60%', '50%'], + data:scope.data, + itemStyle: { + normal: { + color: function(params) { + var colorList = colors; + return colorList[params.dataIndex]; + }, + shadowColor: '#fff', + barBorderRadius: 5 + + }, + emphasis: { + shadowBlur: 10, + shadowOffsetX: 0, + shadowColor: 'rgba(0, 0, 0, 0.5)' + } + } + } + ] + }; + + + if(scope.data.length === 0){ + myChart.setOption(option_nodata); + }else{ + myChart.setOption(option1); + myChart.on('click', function (params) { + // 点击è”动 + scope.build_search(params); + + }); + + } + + } + + if(scope.panel.chart === 'rosepie') { + + myChart = echarts.init(document.getElementById(idd)); + var option2 = { + title: { + show:false, + x: "center" + }, + color:colors, + tooltip: { + trigger: "item", + confine:true, + formatter: "{a}
{b} : {c} ({d}%)" + }, + legend: { + show:scope.panel.eLegend, + x: "left", + orient: scope.panel.arrangement, + textStyle:{ + fontSize:scope.panel.fontsize, + color:'auto' + }, + data: scope.label + }, + label: { + normal: { + formatter: "{b} ({d}%)", + + textStyle:{ + fontSize:scope.panel.fontsize + } + } + }, + labelLine: { + normal: { + smooth: 0.6 + } + }, + + calculable: !0, + series: [{ + name: scope.panel.title, + type: "pie", + roseType: scope.panel.RoseType, + center: ['50%', '60%'], + label: { + normal: { + show: scope.panel.labels + }, + emphasis: { + show: scope.panel.labels + } + }, + lableLine: { + normal: { + show: !0 + }, + emphasis: { + show: !0 + } + }, + data: scope.data, + itemStyle: { + normal: { + color: function(params) { + var colorList = colors; + return colorList[params.dataIndex]; + }, + shadowColor: '#fff', + barBorderRadius: 5 + + } + } + }] + }; + + if(scope.data.length === 0){ + myChart.setOption(option_nodata);}else{ + myChart.setOption(option2); + myChart.on('click', function (params) { + // 点击è”动 + scope.build_search(params); + }); + } + } + + if(scope.panel.chart === 'bar') { + myChart = echarts.init(document.getElementById(idd)); + var option3 = { + color:colors, + tooltip : { + trigger: 'axis', + confine:true, + axisPointer : { // åæ ‡è½´æŒ‡ç¤ºå™¨ï¼Œåæ ‡è½´è§¦å‘æœ‰æ•ˆ + type : 'shadow' // 默认为直线,å¯é€‰ä¸ºï¼š'line' | 'shadow' + } + }, + grid: { + left: '3%', + right: '3%', + bottom: '3%', + top: '6%', + containLabel: true + }, + xAxis : [ + { + type : 'category', + data : scope.label, + axisLine:{ + show:false + }, + axisLabel:{ + show:scope.panel.labels, + textStyle:{ + color:labelcolor ? '#fff':'#4F4F4F', + fontSize:scope.panel.fontsize, + } + }, + axisTick: { + show:false, + alignWithLabel: false + } + } + ], + yAxis : [ + { + type : 'value', + splitLine: { + show :false, + lineStyle:{ + type:'dotted', + axisTick: { + show:false + }, + color: labelcolor ? '#4F4F4F':'#F8F8FF' + } + }, + axisLabel:{ + show:scope.panel.ylabels, + textStyle:{ + color:labelcolor ? '#fff':'#4F4F4F', + fontSize:scope.panel.fontsize+2, + fontStyle: 'italic' + } + }, + nameTextStyle:{ + + color:labelcolor ? '#fff':'#4F4F4F', + + + }, + axisLine:{ + show:false + } + } + ], + series : [ + { + name:scope.panel.title, + type:'bar', + barWidth: '43%', + data:scope.data, + itemStyle: { + normal: { + color: function(params) { + var colorList = colors; + return colorList[params.dataIndex]; + }, + shadowColor: '#fff', + barBorderRadius: 5 + + } + } + } + ] + }; + //æ²¡æœ‰æ•°æ®æ˜¾ç¤ºNO DATA + + if(scope.data.length === 0){ + myChart.setOption(option_nodata);}else{ + myChart.setOption(option3); + myChart.on('click', function (params) { + // 点击è”动 + scope.build_search(params); + }); + } + + } + + if(scope.panel.chart === 'horizontalBar') { + scope.label.reverse(); + myChart = echarts.init(document.getElementById(idd)); + var option33 = { + color: colors, + tooltip : { + trigger: 'axis', + confine:true, + axisPointer : { // åæ ‡è½´æŒ‡ç¤ºå™¨ï¼Œåæ ‡è½´è§¦å‘æœ‰æ•ˆ + type : 'shadow' // 默认为直线,å¯é€‰ä¸ºï¼š'line' | 'shadow' + } + }, + grid: { + left: '3%', + right: '3%', + bottom: '3%', + top: '6%', + containLabel: true + }, + xAxis : [ + { + type : 'value', + splitLine: { + show :false, + lineStyle:{ + type:'dotted', + axisTick: { + show:false + }, + color: labelcolor ? '#4F4F4F':'#F8F8FF' + } + }, + axisLabel:{ + show:true, + textStyle:{ + color:labelcolor ? '#fff':'#4F4F4F', + fontSize:scope.panel.fontsize+2, + fontStyle: 'italic' + } + }, + nameTextStyle:{ + + color:labelcolor ? '#fff':'#4F4F4F', + + + }, + axisLine:{ + show:true, + } + } + ], + yAxis : [ + { + show:scope.panel.ylabels, + type : 'category', + data : scope.label, + axisLine:{ + show:false + }, + axisLabel:{ + inside:!scope.panel.ylabels, + show:scope.panel.ylabels, + textStyle:{ + color:labelcolor ? '#fff':'#4F4F4F', + fontSize:scope.panel.fontsize, + } + }, + axisTick: { + show:false, + alignWithLabel: false + } + } + ], + series : [ + { + name:scope.panel.title, + type:'bar', + barWidth: '43%', + data:scope.data, + itemStyle: { + normal: { + color: function(params) { + var colorList = colors; + return colorList[params.dataIndex]; + }, + shadowColor: '#fff', + barBorderRadius: 5 + + } + }, + label: { + normal: { + show: true, + formatter:scope.panel.ylabels?'{c}':'{b}:{c}', + position: scope.panel.ylabels?'right':'insideLeft', + offset:[0,-2], + textStyle: { + fontWeight:'bold', + color: labelcolor ? '#fff':'#4F4F4F', + fontSize: scope.panel.fontsize + } + } + } + } + ] + }; + //æ²¡æœ‰æ•°æ®æ˜¾ç¤ºNO DATA + + if(scope.data.length === 0){ + myChart.setOption(option_nodata); + }else{ + myChart.setOption(option33); + myChart.on('click', function (params) { + // 点击è”动 + scope.build_search(params); + }); + } + } + + if(scope.panel.chart === 'radar') { + + var radarlabel = []; + + for (var j = 0; j < scope.label.length; j++) { + + radarlabel[j] = {name:scope.label[j],max:scope.maxdata}; + } + + + myChart = echarts.init(document.getElementById(idd)); + + var dataBJ = [scope.radardata]; + + var lineStyle = { + normal: { + width: 1, + opacity: 0.5 + } + }; + + var option4 = { + + title: { + left: 'center', + textStyle: { + color: '#eee' + } + }, + tooltip: { + trigger: 'axis', + position: function (point) { + // 固定在顶部 + return [point[0], '10%']; + } + }, + legend: { + bottom: 5, + itemGap: 20, + textStyle: { + color: '#fff', + fontSize: scope.panel.fontsize + }, + selectedMode: 'single' + }, + radar: { + indicator: radarlabel, + shape: 'circle', + splitNumber: 5, + name: { + textStyle: { + color: labelcolor ?'rgb(238, 197, 102)':'rgba(90, 78, 53)', + fontSize: scope.panel.fontsize + } + }, + splitLine: { + lineStyle: { + color:labelcolor ? [ + 'rgba(238, 197, 102, 0.1)', 'rgba(238, 197, 102, 0.2)', + 'rgba(238, 197, 102, 0.4)', 'rgba(238, 197, 102, 0.6)', + 'rgba(238, 197, 102, 0.8)', 'rgba(238, 197, 102, 1)' + ].reverse():[ + 'rgba(90, 78, 53, 0.1)', 'rgba(90, 78, 53, 0.2)', + 'rgba(90, 78, 53, 0.4)', 'rgba(90, 78, 53, 0.6)', + 'rgba(90, 78, 53, 0.8)', 'rgba(90, 78, 53, 1)' + ].reverse() + } + }, + splitArea: { + show: false + }, + axisLine: { + lineStyle: { + color: labelcolor ?'rgba(238, 197, 102, 0.5)':'rgba(90, 78, 53, 0.5)' + } + } + }, + series: [ + { + name: scope.panel.title, + type: 'radar', + tooltip: { + trigger: 'item' + }, + lineStyle: lineStyle, + data: dataBJ, + itemStyle: { + normal: { + color: '#F9713C' + } + }, + areaStyle: { + normal: { + opacity: 0.1 + } + } + } + ] + }; + if(scope.data.length === 0){ + myChart.setOption(option_nodata); + }else{ + myChart.setOption(option4); + } + } + + if(scope.panel.chart === 'bars'){ + var islength = 0; + if(scope.data.length>5){ + islength =1; + } + + myChart = echarts.init(document.getElementById(idd)); + var option5 = { + tooltip: { + trigger: 'axis', + confine:true, + axisPointer: { + type: 'none' + }, + formatter: function(params) { + return params[0].name + ': ' + params[0].value; + } + }, + color:['#1a75f9', '#1ab0f9', '#42d3f0', '#e59d87', '#759aa0', '#dc6b67', '#efdd79', '#8dc1aa', '#ea7d52', '#8dace7', '#a6a1e1', '#FECDA3', '#FED980','#bcf924','#f9ac24','#8224f9','#24e5f9','#f96524'], + grid: { + left: '0%', + right: '3%', + bottom: '3%', + top: '3%', + containLabel: true + }, + xAxis: { + data: scope.label, + axisTick: { + show: false + }, + axisLine: { + show: false + }, + axisLabel: { + show:scope.panel.labels, + textStyle:{ + color:'#24b2f9', + fontSize:scope.panel.fontsize, + } + } + }, + yAxis: { + splitLine: { + show: false + }, + axisTick: { + show: false + }, + axisLine: { + show: false + }, + axisLabel: { + show: scope.panel.ylabels, + margin:52, + textStyle:{ + color:labelcolor ? '#DCDCDC':'#4F4F4F', + fontSize:scope.panel.fontsize+2, + fontStyle: 'italic' + } + } + }, + //color: ['#1a75f9', '#1a93f9', '#1ab0f9', '#1acef9', '#42d3f0', '#e59d87', '#759aa0', '#dc6b67', '#efdd79', '#8dc1aa', '#ea7d52', '#8dace7', '#a6a1e1', '#FECDA3', '#FED980'], + series: [{ + name: scope.panel.title, + type: 'pictorialBar', + barCategoryGap: islength?'-60%':'-10%', + symbolSize:['120%','100%'], + // symbol: 'path://M0,10 L10,10 L5,0 L0,10 z', + symbol: 'path://M0,10 L10,10 C5.5,10 5.5,5 5,0 C4.5,5 4.5,10 0,10 z', + itemStyle: { + normal: { + color: function(params) { + var colorList = ['#1a75f9', '#1ab0f9', '#42d3f0', '#e59d87', '#759aa0', '#dc6b67', '#efdd79', '#8dc1aa', '#ea7d52', '#8dace7', '#a6a1e1', '#FECDA3', '#FED980','#bcf924','#f9ac24','#8224f9','#24e5f9','#f96524']; + return colorList[params.dataIndex]; + }, + shadowColor: '#fff', + barBorderRadius: 5, + opacity: 0.8 + + }, + emphasis: { + opacity: 1 + } + }, + data: scope.radardata, + z: 10 + }] + }; + if(scope.data.length === 0){ + myChart.setOption(option_nodata); + }else{ + myChart.setOption(option5); + myChart.on('click', function (params) { + // 点击è”动 + scope.build_search(params); + }); + } + + } + + if(scope.panel.chart === 'funnel'){ + + + myChart = echarts.init(document.getElementById(idd)); + var option6 = { + color: ['#1a75f9', '#1a93f9', '#1ab0f9', '#1acef9', '#42d3f0', '#dc6b67', '#efdd79', '#8dc1aa', '#ea7d52', '#8dace7', '#a6a1e1', '#FECDA3', '#FED980','#bcf924','#f9ac24','#8224f9','#24e5f9','#f96524'], + tooltip: { + trigger: 'item', + confine:true, + formatter: "{a}
{b} : {c}%" + }, + + legend: { + show:scope.panel.eLegend, + x: "left", + orient: scope.panel.arrangement, + textStyle:{ + fontSize:scope.panel.fontsize, + color:'auto' + }, + data: scope.label + }, + calculable: true, + series: [ + { + name:scope.panel.title, + type:'funnel', + left: '10%', + top: 6, + //x2: 80, + bottom: 6, + width: '80%', + // height: {totalHeight} - y - y2, + min: 0, + max: scope.maxdata, + sort: scope.panel.order, + gap: 2, + label: { + normal: { + show: scope.panel.labels, + position:'inside', + formatter:'{b}' + }, + emphasis: { + show: scope.panel.labels, + position:'inside', + formatter: '{b}:{c}%', + textStyle: { + + color:'#000' + } + } + }, + labelLine: { + normal: { + show:false, + length: 10, + lineStyle: { + width: 1, + type: 'solid' + } + } + }, + itemStyle: { + normal: { + color: function(params) { + var colorList = ['#1a75f9', '#1a93f9', '#1ab0f9', '#1acef9', '#42d3f0', '#dc6b67', '#efdd79', '#8dc1aa', '#ea7d52', '#8dace7', '#a6a1e1', '#FECDA3', '#FED980','#bcf924','#f9ac24','#8224f9','#24e5f9','#f96524']; + return colorList[params.dataIndex]; + }, + opacity: 0.8 + + }, + emphasis: { + opacity: 1 + } + }, + data: scope.data + + } + ] + }; + + if(scope.data.length === 0){ + myChart.setOption(option_nodata); + }else{ + myChart.setOption(option6); + myChart.on('click', function (params) { + // 点击è”动 + scope.build_search(params); + }); + } + } + + if(scope.panel.chart === 'ebar') { + + myChart = echarts.init(document.getElementById(idd)); + var option7 = { + color: ['#1a75f9', '#1a93f9', '#1ab0f9', '#1acef9', '#42d3f0', '#e59d87', '#759aa0', '#dc6b67', '#efdd79', '#8dc1aa', '#ea7d52', '#8dace7', '#a6a1e1', '#FECDA3', '#FED980'], + tooltip : { + trigger: 'axis', + axisPointer : { // åæ ‡è½´æŒ‡ç¤ºå™¨ï¼Œåæ ‡è½´è§¦å‘æœ‰æ•ˆ + type : 'shadow' // 默认为直线,å¯é€‰ä¸ºï¼š'line' | 'shadow' + } + }, + grid: { + left: '8%', + right: '3%', + bottom: '3%', + top: '6%', + containLabel: true + }, + xAxis : [ + { + type : 'category', + data : scope.label, + axisLine:{ + show:false + }, + axisLabel:{ + show:false, + textStyle:{ + color:'#cde5fe', + fontSize:16, + } + }, + axisTick: { + alignWithLabel: false + } + } + ], + yAxis : [ + { + type : 'value', + splitLine: { + show :true, + lineStyle:{ + type:'dotted', + color: '#0d394a' + } + }, + axisLabel:{ + textStyle:{ + color:labelcolor?'#fff':'#696969', + fontSize:scope.panel.fontsize, + fontStyle: 'italic' + } + + }, + nameTextStyle:{ + + color:'#fff', + + + }, + axisLine:{ + show:false + } + } + ], + series : [ + { + name:'Visit Top 5', + type:'bar', + barWidth: '43%', + data:scope.data, + itemStyle: { + normal: { + color: function(params) { + var colorList = ['#1a75f9', '#1a93f9', '#1ab0f9', '#1acef9', '#42d3f0', '#e59d87', '#759aa0', '#dc6b67', '#efdd79', '#8dc1aa', '#ea7d52', '#8dace7', '#a6a1e1', '#FECDA3', '#FED980']; + return colorList[params.dataIndex]; + }, + shadowColor: '#fff', + barBorderRadius: 5 + + }, + emphasis: { + color: function(params) { + var colorList = ['#ff951f', '#ff951f', '#ff951f', '#ff951f', '#ff951f', '#e59d87', '#759aa0', '#dc6b67', '#efdd79', '#8dc1aa', '#ea7d52', '#8dace7', '#a6a1e1', '#FECDA3', '#FED980']; + return colorList[params.dataIndex]; + }, + shadowColor: '#fff', + barBorderRadius: 5 + + } + } + } + ] + }; + // 使用刚指定的é…ç½®é¡¹å’Œæ•°æ®æ˜¾ç¤ºå›¾è¡¨ã€‚ + if(scope.data.length === 0){ + myChart.setOption(option_nodata);}else{ + myChart.setOption(option7); + myChart.on('click', function (params) { + // æŽ§åˆ¶å°æ‰“å°æ•°æ®çš„åç§° + console.log(params); + scope.build_search(params); + }); + } + } + + if(scope.panel.chart === 'liquidfill') { + myChart = echarts.init(document.getElementById(idd)); + var series = []; + var titles = []; + + for (var k = 0; k < scope.radardata.length; k++) { + + var xla = scope.label[k].replace(" ","\n"); + var x = (k+0.5) / scope.radardata.length * 100 + '%'; + + titles.push({ + text: xla, + textAlign: 'center', + left: x, + bottom: 10, + padding: 0, + textStyle: { + color: labelcolor?'#fff':'#696969', + fontSize: 12, + fontWeight: 'normal' + } + }); + + series.push({ + animation: true, + waveAnimation: true, + + color: ['#178ad9'], + center: [x, '50%'], + radius: '65%', + + type: 'liquidFill', + shape:'path://M229.844,151.547v-166.75c0-11.92-9.662-21.582-21.58-21.582s-21.581,9.662-21.581,21.582v166.75c-9.088,6.654-14.993,17.397-14.993,29.524c0,20.2,16.374,36.575,36.574,36.575c20.199,0,36.574-16.375,36.574-36.575C244.838,168.944,238.932,158.201,229.844,151.547z', + //shape: 'path://M479.232622,0.563387605 C479.232622,0.563387605 581.318924,34.9465747 595.916359,117.247124 C610.513793,199.547674 712.946576,234.277341 712.946576,234.277341 L282.844461,664.379456 C251.594162,695.539776 210.032528,712.700992 165.814244,712.700992 C121.595959,712.700992 80.0620523,695.5408 48.7840267,664.379456 C-15.71599,600.034368 -15.71599,495.32832 48.8117536,430.984256 L479.232622,0.563387605 Z', + outline: { + show: false + }, + amplitude: 3, + waveLength: '20%', + backgroundStyle: { + color: 'none', + borderColor: labelcolor?'#fff':'#696969', + borderWidth: 1 + }, + data: [{ + // -60 到 100 度 + name:scope.label[k], + value: scope.radardata[k] / scope.maxdata, + rawValue: scope.radardata[k] + }], + itemStyle: { + normal: { + shadowBlur: 0 + } + }, + label: { + normal: { + position: 'insideBottom', + distance: 20, + formatter: function(item) { + return ' ' + item.data.rawValue ; + }, + textStyle: { + color: '#178ad9', + fontSize: 15 + } + } + } + }); + } + + // 使用刚指定的é…ç½®é¡¹å’Œæ•°æ®æ˜¾ç¤ºå›¾è¡¨ã€‚ + if(scope.data.length === 0){ + myChart.setOption(option_nodata);}else{ + myChart.setOption({ + tooltip: { + show: true, + confine:true, + formatter: function(item) { + return item.data.name +" : " +item.data.rawValue ; + } + }, + title: titles, + series: series + }); + myChart.on('click', function (params) { + // æŽ§åˆ¶å°æ‰“å°æ•°æ®çš„åç§° + scope.build_search(params); + }); + } + } + + } + } + }; + }); + +}); diff --git a/src/app/panels/query/editor.html b/src/app/panels/query/editor.html old mode 100755 new mode 100644 index c2f49c495..cdf334a61 --- a/src/app/panels/query/editor.html +++ b/src/app/panels/query/editor.html @@ -1,6 +1,12 @@ -
+
+
Linkage Effective
+
+ +
+ + diff --git a/src/app/panels/query/meta.html b/src/app/panels/query/meta.html old mode 100755 new mode 100644 diff --git a/src/app/panels/query/module.html b/src/app/panels/query/module.html old mode 100755 new mode 100644 index d548e179c..9fc1117ab --- a/src/app/panels/query/module.html +++ b/src/app/panels/query/module.html @@ -1,27 +1,28 @@
+
- Pinned - + Pinned + {{querySrv.list[id].alias || querySrv.list[id].query}}
- + +
diff --git a/src/app/panels/query/module.js b/src/app/panels/query/module.js old mode 100755 new mode 100644 index ec02ba967..6bb5afd0e --- a/src/app/panels/query/module.js +++ b/src/app/panels/query/module.js @@ -20,12 +20,7 @@ define([ module.controller('query', function($scope, querySrv, $rootScope) { $scope.panelMeta = { - modals: [{ - description: "Inspect", - icon: "icon-info-sign", - partial: "app/partials/inspector.html", - show: true - }], + status : "Stable", description : "Provide a search bar for free-form queries. You almost certainly want one of these somewhere prominent on your dashboard." }; @@ -34,6 +29,8 @@ define([ var _d = { query : "*:*", pinned : true, + display:'block', + icon:"icon-caret-down", history : [], spyable : true, remember: 10, // max: 100, angular strap can't take a variable for items param @@ -45,11 +42,6 @@ define([ $scope.init = function() { }; - $scope.reset = function() { - $scope.querySrv.list[Object.keys($scope.querySrv.list).length - 1].query = _d.query; - $rootScope.$broadcast('refresh'); - }; - $scope.refresh = function() { update_history(_.pluck($scope.querySrv.list,'query')); $rootScope.$broadcast('refresh'); @@ -58,7 +50,17 @@ define([ $scope.render = function() { $rootScope.$broadcast('render'); }; + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; $scope.toggle_pin = function(id) { querySrv.list[id].pin = querySrv.list[id].pin ? false : true; }; diff --git a/src/app/panels/query/query.css b/src/app/panels/query/query.css old mode 100755 new mode 100644 diff --git a/src/app/panels/rc/editor.html b/src/app/panels/rc/editor.html new file mode 100644 index 000000000..8661b3dd5 --- /dev/null +++ b/src/app/panels/rc/editor.html @@ -0,0 +1,27 @@ +
+ + +
Tooltip Settings
+
+
+ + +
+
\ No newline at end of file diff --git a/src/app/panels/rc/graph.js b/src/app/panels/rc/graph.js new file mode 100644 index 000000000..bb6400b46 --- /dev/null +++ b/src/app/panels/rc/graph.js @@ -0,0 +1,137 @@ + var graph_id = scope.$id; + + var metric = scope.panel.metric_field; + var labelcolor = false; + + if (dashboard.current.style === 'dark'){ + labelcolor = true; + } + + var graph = echarts.init(dobument.getElementById(graph_id)); + + // This variation on ForceDirectedLayout does not move any selected + // Nodes + // but does move all other nodes (vertexes). + function ContinuousForceDirectedLayout() { + go.ForceDirectedLayout.call(this); + this._isObserving = false; + } + go.Diagram.inherit(ContinuousForceDirectedLayout, go.ForceDirectedLayout); + + /** @override */ + ContinuousForceDirectedLayout.prototype.isFixed = function(v) { + return v.node.isSelected; + } + + // optimization: reuse the ForceDirectedNetwork rather than re-create it + // each time + /** @override */ + ContinuousForceDirectedLayout.prototype.doLayout = function(coll) { + if (!this._isObserving) { + this._isObserving = true; + // cacheing the network means we need to recreate it if nodes or + // links have been added or removed or relinked, + // so we need to track structural model changes to discard the saved + // network. + var lay = this; + this.diagram.addModelChangedListener(function (e) { + // modelChanges include a few cases that we don't actually care + // about, such as + // "nodeCategory" or "linkToPortId", but we'll go ahead and recreate + // the network anyway. + // Also clear the network when replacing the model. + if (e.modelChange !== "" || (e.change === go.ChangedEvent.Transaction && e.propertyName === "StartingFirstTransaction")) { + lay.network = null; + } + }); + } + var net = this.network; + if (net === null) { // the first time, just create the network as + // normal + this.network = net = this.makeNetwork(coll); + } else { // but on reuse we need to update the LayoutVertex.bounds + // for selected nodes + this.diagram.nodes.each(function (n) { + var v = net.findVertex(n); + if (v !== null) v.bounds = n.actualBounds; + }); + } + // now perform the normal layout + go.ForceDirectedLayout.prototype.doLayout.call(this, coll); + // doLayout normally discards the LayoutNetwork by setting + // Layout.network to null; + // here we remember it for next time + this.network = net; + } + // end ContinuousForceDirectedLayout + + function drawGraph(nodeDataArray, linkDataArray, graph_id) { + var $ = go.GraphObject.make; // for conciseness in defining templates + + myDiagram = + $(go.Diagram, graph_id, // create a Diagram for the DIV HTML + // element + { + initialAutoScale: go.Diagram.Uniform, // an initial automatic + // zoom-to-fit + contentAlignment: go.Spot.Center, // align document to the + // center of the + // viewport + layout: + $(ContinuousForceDirectedLayout, // automatically spread + // nodes apart while + // dragging + { defaultSpringLength: 30, defaultElectricalCharge: 100 }), + // do an extra layout at the end of a move + "SelectionMoved": function(e) { e.diagram.layout.invalidateLayout(); } + }); + + myDiagram.toolManager.draggingTool.doMouseMove = function() { + go.DraggingTool.prototype.doMouseMove.call(this); + if (this.isActive) { this.diagram.layout.invalidateLayout(); } + } + + // These nodes have text surrounded by a rounded rectangle + // whose fill color is bound to the node data. + // The user can drag a node by dragging its TextBlock label. + // Dragging from the Shape will start drawing a new link. + myDiagram.nodeTemplate = + $(go.Node, "Auto", // the whole node panel define the node's outer shape, which will surround the TextBlock + $(go.Shape, "Circle", + { fill: "CornflowerBlue", stroke: "black", spot1: new go.Spot(0, 0, 5, 5), spot2: new go.Spot(1, 1, -5, -5) }), + $(go.TextBlock, + { font: "bold 10pt helvetica, bold arial, sans-serif", textAlign: "center", maxSize: new go.Size(100, NaN) }, + new go.Binding("text", "key")), + { + click: function(e, obj) { window.selected_var=obj.part.data.key;showMessage(obj.part.data.key); }, + selectionChanged: function(part) { + var shape = part.elt(0); + shape.fill = part.isSelected ? "red" : "CornflowerBlue"; + } + } + ); + + // The link shape and arrowhead have their stroke brush data + // bound to the "color" property + myDiagram.linkTemplate = + $(go.Link, // the whole link panel + $(go.Shape, // the link shape + { stroke: "black" }), + $(go.Shape, // the arrowhead + { toArrow: "standard", stroke: null }) + ); + myDiagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray); + } + + function reload() { + //myDiagram.layout.network = null; + var text = myDiagram.model.toJson(); + myDiagram.model = go.Model.fromJson(text); + //myDiagram.layout = + // go.GraphObject.make(ContinuousForceDirectedLayout, // automatically spread nodes apart while dragging + // { defaultSpringLength: 30, defaultElectricalCharge: 100 }); + } + + function showMessage(s) { + alert("klick: "+s+"."); + } diff --git a/src/app/panels/rc/heatmap.html b/src/app/panels/rc/heatmap.html new file mode 100644 index 000000000..e89dba85b --- /dev/null +++ b/src/app/panels/rc/heatmap.html @@ -0,0 +1,409 @@ + + + + + + +Order: + + +
+ + \ No newline at end of file diff --git a/src/app/panels/rc/interval.js b/src/app/panels/rc/interval.js new file mode 100644 index 000000000..673371fcf --- /dev/null +++ b/src/app/panels/rc/interval.js @@ -0,0 +1,57 @@ +define([ + 'kbn' +], +function (kbn) { + 'use strict'; + + /** + * manages the interval logic + * @param {[type]} interval_string An interval string in the format '1m', '1y', etc + */ + function Interval(interval_string) { + this.string = interval_string; + + var info = kbn.describe_interval(interval_string); + this.type = info.type; + this.ms = info.sec * 1000 * info.count; + + // does the length of the interval change based on the current time? + if (this.type === 'y' || this.type === 'M') { + // we will just modify this time object rather that create a new one constantly + this.get = this.get_complex; + this.date = new Date(0); + } else { + this.get = this.get_simple; + } + } + + Interval.prototype = { + toString: function () { + return this.string; + }, + after: function(current_ms) { + return this.get(current_ms, 1); + }, + before: function (current_ms) { + return this.get(current_ms, -1); + }, + get_complex: function (current, delta) { + this.date.setTime(current); + switch(this.type) { + case 'M': + this.date.setUTCMonth(this.date.getUTCMonth() + delta); + break; + case 'y': + this.date.setUTCFullYear(this.date.getUTCFullYear() + delta); + break; + } + return this.date.getTime(); + }, + get_simple: function (current, delta) { + return current + (delta * this.ms); + } + }; + + return Interval; + +}); \ No newline at end of file diff --git a/src/app/panels/rc/module.html b/src/app/panels/rc/module.html new file mode 100644 index 000000000..086e76cf8 --- /dev/null +++ b/src/app/panels/rc/module.html @@ -0,0 +1,45 @@ +
+ + + + +
+
\ No newline at end of file diff --git a/src/app/panels/rc/module.js b/src/app/panels/rc/module.js new file mode 100644 index 000000000..109e02ec0 --- /dev/null +++ b/src/app/panels/rc/module.js @@ -0,0 +1,458 @@ +/* + + ## Anomaly Detection + + ### Parameters + * auto_int :: Auto calculate data point interval? + * resolution :: If auto_int is enables, shoot for this many data points, rounding to + sane intervals + * interval :: Datapoint interval in elasticsearch date math format (eg 1d, 1w, 1y, 5y) + * fill :: Only applies to line charts. Level of area shading from 0-10 + * linewidth :: Only applies to line charts. How thick the line should be in pixels + While the editor only exposes 0-10, this can be any numeric value. + Set to 0 and you'll get something like a scatter plot + * timezone :: This isn't totally functional yet. Currently only supports browser and utc. + browser will adjust the x-axis labels to match the timezone of the user's + browser + * spyable :: Dislay the 'eye' icon that show the last elasticsearch query + * zoomlinks :: Show the zoom links? + * bars :: Show bars in the chart + * stack :: Stack multiple queries. This generally a crappy way to represent things. + You probably should just use a line chart without stacking + * points :: Should circles at the data points on the chart + * lines :: Line chart? Sweet. + * legend :: Show the legend? + * x-axis :: Show x-axis labels and grid lines + * y-axis :: Show y-axis labels and grid lines + * interactive :: Allow drag to select time range + +*/ +define([ + 'angular', + 'app', + 'jquery', + 'underscore', + 'kbn', + 'moment', + './timeSeries' +], +function (angular, app, $, _, kbn, moment, timeSeries) { + 'use strict'; + var module = angular.module('kibana.panels.rc', []); + app.useModule(module); + + var DEBUG = true; + console.log('DEBUG : ' + DEBUG); + module.controller('rc', function($scope, $q, $http, querySrv, dashboard, filterSrv, alertSrv) { + $scope.panelMeta = { + modals : [ + { + description: "Inspect", + icon: "icon-info-sign", + partial: "app/partials/inspector.html", + show: $scope.panel.spyable + } + ], + editorTabs : [ + { + title:'Queries', + src:'app/partials/querySelect.html' + } + ], + status : "Stable", + description : "A bucketed time series chart of the current query, including all applied time and non-time filters, when used in count mode. Uses Solr’s facet.range query parameters. In values mode, it plots the value of a specific field over time, and allows the user to group field values by a second field." + }; + + // Set and populate defaults + var _d = { + mode : 'value', + queries : { + mode : 'all', + ids : [], + query : '*:*', + custom : '' + }, + max_rows : 1000, // maximum number of rows returned from Solr (also use this for group.limit to simplify UI setting) + reverse : 0, + group_field : null, + auto_int : true, + total_first : '%', + fontsize : 20, + field_color : '#209bf8', + resolution : 100, + value_sort : 'rs_timestamp', + interval : '5m', + intervals : ['auto','1s','1m','5m','10m','30m','1h','3h','12h','1d','1w','1M','1y'], + fill : 0, + linewidth : 3, + chart : 'stacking', + chartColors : ['#209bf8', '#f4d352','#ccf452','#8cf452','#3cee2b','#f467d8','#2fd7ee'], + timezone : 'browser', // browser, utc or a standard timezone + spyable : true, + zoomlinks : true, + bars : true, + stack : true, + label : true, + points : false, + lines : false, + lines_smooth: false, // Enable 'smooth line' mode by removing zero values from the plot. + legend : true, + 'x-axis' : true, + 'y-axis' : true, + percentage : false, + interactive : true, + options : true, + show_queries: true, + tooltip : { + value_type: 'cumulative', + query_as_alias: false + }, + jobid : '', + job_status: 'Ready', + }; + + _.defaults($scope.panel,_d); + + $scope.init = function() { + // Hide view options by default + if (DEBUG) console.log('init'); + $scope.options = false; + $scope.$on('refresh',function(){ + $scope.get_data(); + }); + + $scope.get_data(); + + }; + + $scope.set_interval = function(interval) { + if(interval !== 'auto') { + $scope.panel.auto_int = false; + $scope.panel.interval = interval; + } else { + $scope.panel.auto_int = true; + } + }; + + $scope.interval_label = function(interval) { + return $scope.panel.auto_int && interval === $scope.panel.interval ? interval+" (auto)" : interval; + }; + + $scope.set_refresh = function (state) { + $scope.refresh = state; + // if 'count' mode is selected, set decimal_points to zero automatically. + if ($scope.panel.mode === 'count') { + $scope.panel.decimal_points = 0; + } + $scope.get_data(); + }; + + /** + * The time range effecting the panel + * @return {[type]} [description] + */ + $scope.get_time_range = function () { + var range = $scope.range = filterSrv.timeRange('min'); + return range; + }; + + $scope.get_interval = function () { + var interval = $scope.panel.interval, + range; + if ($scope.panel.auto_int) { + range = $scope.get_time_range(); + if (range) { + interval = kbn.secondsToHms( + kbn.calculate_interval(range.from, range.to, $scope.panel.resolution, 0) / 1000 + ); + } + } + $scope.panel.interval = interval || '10m'; + return $scope.panel.interval; + }; + + $scope.build_anomaly_query = function(filetype, isForExport) { + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + } + if (dashboard.current.anomaly_fq) { + fq = fq + '&' + dashboard.current.anomaly_fq; + } + var wt_json = '&wt=' + filetype; + var rows_limit = isForExport ? '&rows=0' : ''; // for terms, we do not need the actual response doc, so set rows=0 + var facet = ''; + return querySrv.getORquery() + wt_json + rows_limit + fq + facet + ($scope.panel.queries.custom !== null ? $scope.panel.queries.custom : ''); + }; + + /** + * Fetch the data for a chunk of a queries results. Multiple segments occur when several indicies + * need to be consulted (like timestamped logstash indicies) + * + * The results of this function are stored on the scope's data property. This property will be an + * array of objects with the properties info, time_series, and hits. These objects are used in the + * render_panel function to create the historgram. + * + * !!! Solr does not need to fetch the data in chunk because it uses a facet search and retrieve + * !!! all events from a single query. + * + * @param {number} segment The segment count, (0 based) + * @param {number} query_id The id of the query, generated on the first run and passed back when + * this call is made recursively for more segments + */ + $scope.get_data = function(segment, query_id) { + if (DEBUG) console.log('get data start.'); + if (_.isUndefined(segment)) { + segment = 0; + } + delete $scope.panel.error; + + // Make sure we have everything for the request to complete + if(dashboard.indices.length === 0) { + return; + } + var _range = $scope.get_time_range(); + var _interval = $scope.get_interval(_range); + + if ($scope.panel.auto_int) { + $scope.panel.interval = kbn.secondsToHms( + kbn.calculate_interval(_range.from,_range.to,$scope.panel.resolution,0)/1000); + } + + $scope.panelMeta.loading = true; + + // Solr + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + var request = $scope.sjs.Request().indices(dashboard.indices[segment]); + // $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + + + $scope.panel.queries.query = ""; + // Build the query + _.each($scope.panel.queries.ids, function(id) { + var query = $scope.sjs.FilteredQuery( + querySrv.getEjsObj(id), + filterSrv.getBoolFilter(filterSrv.ids) + ); + var facet = $scope.sjs.DateHistogramFacet(id); + }); + + if(_.isNull($scope.panel.value_field)) { + $scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified"; + return; + } + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + } + + var time_field = filterSrv.getTimeField(); + var start_time = filterSrv.getStartTime(); + var end_time = filterSrv.getEndTime(); + + $scope.panel.start_time = start_time; + $scope.panel.end_time = end_time; + + // facet.range.end does NOT accept * as a value, need to convert it to NOW + if (end_time === '*') { + end_time = 'NOW'; + } + + //*********************************** 拼查询url************ + var wt_json = '&wt=json'; + // var metric_field = $scope.panel.metric_field; + //var anomaly_th = $scope.panel.anomaly_th; + var sort_field = '&sort='+'timestamp_l'+'%20asc'; + //var rows_limit = '&rows='+$scope.panel.max_rows; + // var facet = ''; + //var fl = '&fl=' + 'timestamp_l%20anomaly_value_d%20value_d'; + var fl = '&fl=' + 'nodes_s%20edges_s%20query_list'; + //fq = fq + '&fq=anomaly_value_d:[' + anomaly_th + '%20TO%20*]'; + + //*********************************** end ******************* + + var mypromises = []; + //var temp_q = 'q=' + metric_field + ':' + metric + wt_json + rows_limit + fq + facet + fl + sort_field; + var query_list = []; + + var temp_q = 'q=' + 'result_s:bn' + wt_json ; + query_list.push(temp_q); + + for (var i = 0; i < query_list.length; i++) { + + $scope.panel.queries.query += query_list[i] + "\n"; + + if ($scope.panel.queries.custom !== null) { + request = request.setQuery(query_list[i] + $scope.panel.queries.custom); + } else { + request = request.setQuery(query_list[i]); + } + mypromises.push(request.doSearch()); + } + + $scope.data = []; + if (dashboard.current.services.query.ids.length >= 1) { + $q.all(mypromises).then(function(results) { + if (DEBUG) console.log(results); + $scope.panelMeta.loading = false; + // Convert facet ids to numbers + // var facetIds = _.map(_.keys(results.facets),function(k){return parseInt(k, 10);}); + //var facetIds = [0]; // Need to fix this + + // Make sure we're still on the same query/queries + // TODO: We probably DON'T NEED THIS unless we have to support multiple queries in query module. + // if ($scope.query_id === query_id && _.difference(facetIds, $scope.panel.queries.ids).length === 0) { + var time_series, hits; + for (var i = 0; i < query_list.length; i++) { + if (!(_.isUndefined(results[i].error))) { + $scope.panel.error = $scope.parse_error(results[i].error.msg); + return; + } + $scope.data[i] = results[i].response.docs; + if (DEBUG) console.log($scope.data[i]); + } + // Tell the histogram directive to render. + $scope.$emit('render'); + }); + } + }; + }); + + module.directive('rcChart', function(querySrv,dashboard,filterSrv) { + return { + restrict: 'A', + link: function(scope, elem) { + var myChart; + // Receive render events + scope.$on('render',function(){ + render_panel(); + }); + + // Re-render if the window is resized + angular.element(window).bind('resize', function(){ + render_panel(); + }); + + // Function for rendering panel + function render_panel() { + var plot, chartData; + var colors = []; + + // IE doesn't work without this + elem.css({height:scope.panel.height||scope.row.height}); + + // Make a clone we can operate on. + + chartData = _.clone(scope.data); + chartData = scope.panel.missing ? chartData : + _.without(chartData,_.findWhere(chartData,{meta:'missing'})); + chartData = scope.panel.other ? chartData : + _.without(chartData,_.findWhere(chartData,{meta:'other'})); + var cause_string = chartData[0][0][dashboard.current.bn_main_node+"_s"]; + var attr = []; + var values = []; + var cause2 = cause_string.split(","); + + for (var i = 0; i < cause2.length; i++) { + var tmp = cause2[i].split(":"); + // alert(tmp[0]); + // alert(tmp[1]); + attr.push(tmp[0]); + values.push(parseFloat(tmp[1])); + } + + var graph_id = scope.$id; + + require(['echarts'], function(ec){ + var echarts = ec; + if(myChart){ + myChart.dispose(); + } + var labelcolor = false; + if (dashboard.current.style === 'dark'){ + labelcolor = true; + } + var query_list = chartData[0][0].query_list_s.split("^"); + myChart = echarts.init(document.getElementById(graph_id)); + var x = parseInt(dashboard.current.bn_main_node); + drawRelationChart(myChart, attr, values, query_list[x] + " çš„æ ¹æºæ€§æŽ’åº"); + + }); + function drawRelationChart(myChart,attr, values, title_name) { + + var option = { + title: { + text: title_name + }, + + tooltip: { + trigger: 'axis', + axisPointer: { + type: 'shadow' + } + }, + + grid: { + left: '3%', + right: '4%', + bottom: '3%', + containLabel: true + }, + + toolbox: { + show: true, + feature: { + dataView: { + show: true + }, + restore: { + show: true + }, + dataZoom: { + show: true + }, + // saveAsImage: { + // show: true + // }, + // magicType: { + // type: ['line', 'bar'] + // } + }, + + }, + + xAxis: { + type: 'value', + boundaryGap: [0, 0.01], + 'min' : 0, + 'max': 2 + }, + + yAxis: { + type: 'category', + data: attr + }, + + series: [{ + name: title_name, + type: 'bar', + data: values + }] + }; + + myChart.setOption(option); + } + + + + + } + } + }; + }); + + +}); diff --git a/src/app/panels/rc/timeSeries.js b/src/app/panels/rc/timeSeries.js new file mode 100644 index 000000000..722768e22 --- /dev/null +++ b/src/app/panels/rc/timeSeries.js @@ -0,0 +1,178 @@ +define([ + 'underscore', + './interval' +], +function (_, Interval) { + 'use strict'; + + var ts = {}; + + // map compatable parseInt + function base10Int(val) { + return parseInt(val, 10); + } + + // trim the ms off of a time, but return it with empty ms. + function getDatesTime(date) { + return Math.floor(date.getTime() / 1000)*1000; + } + /** + * Certain graphs require 0 entries to be specified for them to render + * properly (like the line graph). So with this we will caluclate all of + * the expected time measurements, and fill the missing ones in with 0 + * @param {object} opts An object specifying some/all of the options + * + * OPTIONS: + * @opt {string} interval The interval notion describing the expected spacing between + * each data point. + * @opt {date} start_date (optional) The start point for the time series, setting this and the + * end_date will ensure that the series streches to resemble the entire + * expected result + * @opt {date} end_date (optional) The end point for the time series, see start_date + * @opt {string} fill_style Either "minimal", or "all" describing the strategy used to zero-fill + * the series. + */ + ts.ZeroFilled = function (opts) { + opts = _.defaults(opts, { + interval: '10m', + start_date: null, + end_date: null, + fill_style: 'minimal' + }); + + // the expected differenece between readings. + this.interval = new Interval(opts.interval); + + // will keep all values here, keyed by their time + this._data = {}; + this.start_time = opts.start_date && getDatesTime(opts.start_date); + this.end_time = opts.end_date && getDatesTime(opts.end_date); + this.opts = opts; + }; + + /** + * Add a row + * @param {int} time The time for the value, in + * @param {any} value The value at this time + */ + ts.ZeroFilled.prototype.addValue = function (time, value) { + if (time instanceof Date) { + time = getDatesTime(time); + } else { + time = base10Int(time); + } + if (!isNaN(time)) { + this._data[time] = (_.isUndefined(value) ? 0 : value); + } + this._cached_times = null; + }; + + /** + * Get an array of the times that have been explicitly set in the series + * @param {array} include (optional) list of timestamps to include in the response + * @return {array} An array of integer times. + */ + ts.ZeroFilled.prototype.getOrderedTimes = function (include) { + var times = _.map(_.keys(this._data), base10Int); + if (_.isArray(include)) { + times = times.concat(include); + } + return _.uniq(times.sort(function (a, b) { + // decending numeric sort + return a - b; + }), true); + }; + + /** + * return the rows in the format: + * [ [time, value], [time, value], ... ] + * + * Heavy lifting is done by _get(Min|All)FlotPairs() + * @param {array} required_times An array of timestamps that must be in the resulting pairs + * @return {array} + */ + ts.ZeroFilled.prototype.getFlotPairs = function (required_times) { + var times = this.getOrderedTimes(required_times), + strategy, + pairs; + + if(this.opts.fill_style === 'all') { + strategy = this._getAllFlotPairs; + } else { + strategy = this._getMinFlotPairs; + } + + pairs = _.reduce( + times, // what + strategy, // how + [], // where + this // context + ); + + // if the first or last pair is inside either the start or end time, + // add those times to the series with null values so the graph will stretch to contain them. + if (this.start_time && (pairs.length === 0 || pairs[0][0] > this.start_time)) { + pairs.unshift([this.start_time, null]); + } + if (this.end_time && (pairs.length === 0 || pairs[pairs.length - 1][0] < this.end_time)) { + pairs.push([this.end_time, null]); + } + + return pairs; + }; + + /** + * ** called as a reduce stragegy in getFlotPairs() ** + * Fill zero's on either side of the current time, unless there is already a measurement there or + * we are looking at an edge. + * @return {array} An array of points to plot with flot + */ + ts.ZeroFilled.prototype._getMinFlotPairs = function (result, time, i, times) { + var next, expected_next, prev, expected_prev; + + // check for previous measurement + if (i > 0) { + prev = times[i - 1]; + expected_prev = this.interval.before(time); + if (prev < expected_prev) { + result.push([expected_prev, 0]); + } + } + + // add the current time + result.push([ time, this._data[time] || 0 ]); + + // check for next measurement + if (times.length > i) { + next = times[i + 1]; + expected_next = this.interval.after(time); + if (next > expected_next) { + result.push([expected_next, 0]); + } + } + + return result; + }; + + /** + * ** called as a reduce stragegy in getFlotPairs() ** + * Fill zero's to the right of each time, until the next measurement is reached or we are at the + * last measurement + * @return {array} An array of points to plot with flot + */ + ts.ZeroFilled.prototype._getAllFlotPairs = function (result, time, i, times) { + var next, expected_next; + + result.push([ times[i], this._data[times[i]] || 0 ]); + next = times[i + 1]; + expected_next = this.interval.after(time); + for(; times.length > i && next > expected_next; expected_next = this.interval.after(expected_next)) { + result.push([expected_next, 0]); + } + + return result; + }; + + + return ts; +}); \ No newline at end of file diff --git a/src/app/panels/sankey/editor.html b/src/app/panels/sankey/editor.html new file mode 100644 index 000000000..39301e907 --- /dev/null +++ b/src/app/panels/sankey/editor.html @@ -0,0 +1,129 @@ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + + +
+
+ + +
+ +
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+
+
Real-time (Auto-refresh)
+
+ +
+
+ + +
+
+
+
Linkage Effective
+
+ +
+ +
diff --git a/src/app/panels/sankey/module.html b/src/app/panels/sankey/module.html new file mode 100644 index 000000000..91388ac2f --- /dev/null +++ b/src/app/panels/sankey/module.html @@ -0,0 +1,116 @@ +
+ + +
+ + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
Term{{panel.mode | capitalize}}Action
{{term.label}}{{term.data[0][1].toFixed(panel.decimal_points)}} + + + + +
+ + +
+
+
diff --git a/src/app/panels/sankey/module.js b/src/app/panels/sankey/module.js new file mode 100644 index 000000000..bb9a436fc --- /dev/null +++ b/src/app/panels/sankey/module.js @@ -0,0 +1,646 @@ +/* + ## sankey + + ### Parameters + * style :: A hash of css styles + * size :: top N + * arrangement :: How should I arrange the query results? 'horizontal' or 'vertical' + * chart :: Show a chart? 'none', 'bar', 'pie' + * donut :: Only applies to 'pie' charts. Punches a hole in the chart for some reason + * tilt :: Only 'pie' charts. Janky 3D effect. Looks terrible 90% of the time. + * lables :: Only 'pie' charts. Labels on the pie? +*/ +define([ + 'angular', + 'app', + 'underscore', + 'jquery', + 'kbn' +], +function (angular, app, _, $, kbn) { + 'use strict'; + + var module = angular.module('kibana.panels.sankey', []); + app.useModule(module); + + module.controller('sankey', function($scope, $timeout, timer, querySrv, dashboard, filterSrv) { + $scope.panelMeta = { + + exportfile: true, + editorTabs : [ + {title:'Queries', src:'app/partials/querySelect.html'} + ], + status : "Stable", + description : "Displays the results of a Solr facet as a pie chart, bar chart, or a table. Newly added functionality displays min/max/mean/sum of a stats field, faceted by the Solr facet field, again as a pie chart, bar chart or a table." + }; + + // Set and populate defaults + var _d = { + queries : { + mode : 'all', + ids : [], + query : '*:*', + custom : '' + }, + mode : 'count', // mode to tell which number will be used to plot the chart. + field : '', + stats_field : '', + decimal_points : 0, // The number of digits after the decimal point + exclude : [], + missing : false, + other : false, + size : 10000, + sortBy : 'count', + order : 'descending', + fontsize : 12, + linkage_id:'a', + donut : false, + tilt : false, + labels : true, + display:'block', + icon:"icon-caret-down", + ylabels :true, + logAxis : false, + arrangement : 'vertical', + RoseType : 'area', + chart : 'sankey', + sankeymode :'count', + exportSize : 10000, + lastColor : '', + spyable : true, + show_queries:true, + error : '', + chartColors : querySrv.colors, + refresh: { + enable: false, + interval: 2 + } + }; + _.defaults($scope.panel,_d); + + $scope.init = function () { + $scope.hits = 0; + //$scope.testMultivalued(); + + // Start refresh timer if enabled + if ($scope.panel.refresh.enable) { + $scope.set_timer($scope.panel.refresh.interval); + } + + $scope.$on('refresh',function(){ + $scope.get_data(); + }); + + $scope.get_data(); + }; + + $scope.testMultivalued = function() { + if($scope.panel.field && $scope.fields.typeList[$scope.panel.field] && $scope.fields.typeList[$scope.panel.field].schema.indexOf("M") > -1) { + $scope.panel.error = "Can't proceed with Multivalued field"; + return; + } + + if($scope.panel.stats_field && $scope.fields.typeList[$scope.panel.stats_field].schema.indexOf("M") > -1) { + $scope.panel.error = "Can't proceed with Multivalued field"; + return; + } + }; + + /** + * + * + * @param {String} filetype -'json', 'xml', 'csv' + */ + $scope.build_query = function(filetype, isForExport) { + + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + } + var wt_json = '&wt=' + filetype; + var rows_limit = isForExport ? '&rows=0' : ''; // for sankey, we do not need the actual response doc, so set rows=0 + var facet = ''; + + if ($scope.panel.mode === 'count') { + facet = '&facet=true&facet.field=' + $scope.panel.field + '&facet.limit=' + $scope.panel.size + '&facet.missing=true'; + } else { + // if mode != 'count' then we need to use stats query + // stats does not support something like facet.limit, so we have to sort and limit the results manually. + facet = '&stats=true&stats.facet=' + $scope.panel.field + '&stats.field=' + $scope.panel.stats_field + '&facet.missing=true'; + } + facet += '&f.' + $scope.panel.field + '.facet.sort=' + ($scope.panel.sortBy || 'count'); + + var exclude_length = $scope.panel.exclude.length; + var exclude_filter = ''; + if(exclude_length > 0){ + for (var i = 0; i < exclude_length; i++) { + if($scope.panel.exclude[i] !== "") { + exclude_filter += '&fq=-' + $scope.panel.field +":"+ $scope.panel.exclude[i]; + } + } + } + + return querySrv.getORquery() + wt_json + rows_limit + fq + exclude_filter + facet + ($scope.panel.queries.custom != null ? $scope.panel.queries.custom : ''); + }; + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; + $scope.exportfile = function(filetype) { + + var query = this.build_query(filetype, true); + + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + var request = $scope.sjs.Request().indices(dashboard.indices), + response; + + request.setQuery(query); + + response = request.doSearch(); + + // Populate scope when we have results + response.then(function(response) { + kbn.download_response(response, filetype, "sankey"); + }); + }; + + $scope.set_timer = function(refresh_interval) { + $scope.panel.refresh.interval = refresh_interval; + if (_.isNumber($scope.panel.refresh.interval)) { + timer.cancel($scope.refresh_timer); + $scope.realtime(); + } else { + timer.cancel($scope.refresh_timer); + } + }; + + $scope.realtime = function() { + if ($scope.panel.refresh.enable) { + timer.cancel($scope.refresh_timer); + + $scope.refresh_timer = timer.register($timeout(function() { + $scope.realtime(); + $scope.get_data(); + }, $scope.panel.refresh.interval*1000)); + } else { + timer.cancel($scope.refresh_timer); + } + }; + + $scope.get_data = function() { + if(($scope.panel.linkage_id === dashboard.current.linkage_id)||dashboard.current.enable_linkage){ + // Make sure we have everything for the request to complete + if (dashboard.indices.length === 0) { + return; + } + + delete $scope.panel.error; + $scope.panelMeta.loading = true; + var request, results; + + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + request = $scope.sjs.Request().indices(dashboard.indices); + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + + // Populate the inspector panel + $scope.inspector = angular.toJson(JSON.parse(request.toString()), true); + + var query = this.build_query('json', false); + + // Set the panel's query + $scope.panel.queries.query = query; + + request.setQuery(query); + + results = request.doSearch(); + + // Populate scope when we have results + results.then(function (results) { + // Check for error and abort if found + if (!(_.isUndefined(results.error))) { + $scope.panel.error = $scope.parse_error(results.error.msg); + $scope.data = []; + $scope.panelMeta.loading = false; + $scope.$emit('render'); + return; + } + + // Function for validating HTML color by assign it to a dummy
+ // and let the browser do the work of validation. + var isValidHTMLColor = function (color) { + // clear attr first, before comparison + $('#colorTest').removeAttr('style'); + var valid = $('#colorTest').css('color'); + $('#colorTest').css('color', color); + + if (valid === $('#colorTest').css('color')) { + return false; + } else { + return true; + } + }; + + // Function for customizing chart color by using field values as colors. + var addSliceColor = function (slice, color) { + if ($scope.panel.useColorFromField && isValidHTMLColor(color)) { + slice.color = color; + } + return slice; + }; + + var sum = 0; + var k = 0; + var missing = 0; + $scope.panelMeta.loading = false; + $scope.hits = results.response.numFound; + $scope.data = []; + + if ($scope.panel.mode === 'count') { + // In count mode, the y-axis min should be zero because count value cannot be negative. + $scope.yaxis_min = 0; + _.each(results.facet_counts.facet_fields, function (v) { + for (var i = 0; i < v.length; i++) { + var term = v[i]; + i++; + var count = v[i]; + sum += count; + if (term === null) { + missing = count; + } else { + // if count = 0, do not add it to the chart, just skip it + if (count === 0) { + continue; + } + var slice = {label: term, data: [[k, count]], actions: true}; + slice = addSliceColor(slice, term); + $scope.data.push(slice); + } + } + }); + } else { + // In stats mode, set y-axis min to null so jquery.flot will set the scale automatically. + $scope.yaxis_min = null; + _.each(results.stats.stats_fields[$scope.panel.stats_field].facets[$scope.panel.field], function (stats_obj, facet_field) { + var slice = {label: facet_field, data: [[k, stats_obj[$scope.panel.mode]]], actions: true}; + $scope.data.push(slice); + }); + } + // Sort the results + $scope.data = _.sortBy($scope.data, function (d) { + return $scope.panel.sortBy === 'index' ? d.label : d.data[0][1]; + }); + if ($scope.panel.order === 'descending') { + $scope.data.reverse(); + } + + // Slice it according to panel.size, and then set the x-axis values with k. + $scope.data = $scope.data.slice(0, $scope.panel.size); + _.each($scope.data, function (v) { + v.data[0][0] = k; + k++; + }); + + if ($scope.panel.field && $scope.fields.typeList[$scope.panel.field] && $scope.fields.typeList[$scope.panel.field].schema.indexOf("T") > -1) { + $scope.hits = sum; + } + + $scope.data.push({ + label: 'Missing field', + // data:[[k,results.facets.sankey.missing]],meta:"missing",color:'#aaa',opacity:0}); + // TODO: Hard coded to 0 for now. Solr faceting does not provide 'missing' value. + data: [[k, missing]], meta: "missing", color: '#aaa', opacity: 0 + }); + $scope.data.push({ + label: 'Other values', + // data:[[k+1,results.facets.sankey.other]],meta:"other",color:'#444'}); + // TODO: Hard coded to 0 for now. Solr faceting does not provide 'other' value. + data: [[k + 1, $scope.hits - sum]], meta: "other", color: '#444' + }); + + $scope.$emit('render'); + }); + } + }; + + $scope.build_search = function(term,negate) { + + if (_.isUndefined(term.meta)) { + filterSrv.set({ + type: 'sankey', field: $scope.panel.field, value: term.label, + mandate: (negate ? 'mustNot' : 'must') + }); + } else if (term.meta === 'missing') { + filterSrv.set({ + type: 'exists', field: $scope.panel.field, + mandate: (negate ? 'must' : 'mustNot') + }); + } else { + return; + } + + dashboard.current.linkage_id = $scope.panel.linkage_id; + dashboard.current.enable_linkage = false; + dashboard.refresh(); + + }; + + $scope.set_refresh = function (state) { + $scope.refresh = state; + // if 'count' mode is selected, set decimal_points to zero automatically. + if ($scope.panel.mode === 'count') { + $scope.panel.decimal_points = 0; + } + }; + + $scope.close_edit = function() { + // Start refresh timer if enabled + if ($scope.panel.refresh.enable) { + $scope.set_timer($scope.panel.refresh.interval); + } + + if ($scope.refresh) { + // $scope.testMultivalued(); + $scope.get_data(); + } + $scope.refresh = false; + $scope.$emit('render'); + }; + + $scope.showMeta = function(term) { + if(_.isUndefined(term.meta)) { + return true; + } + if(term.meta === 'other' && !$scope.panel.other) { + return false; + } + if(term.meta === 'missing' && !$scope.panel.missing) { + return false; + } + return true; + }; + + }); + + module.directive('sankeyChart', function(querySrv,dashboard,filterSrv) { + return { + restrict: 'A', + link: function(scope, elem) { + + // Receive render events + scope.$on('render',function(){ + render_panel(); + }); + + // Re-render if the window is resized + angular.element(window).bind('resize', function(){ + render_panel(); + }); + + // Function for rendering panel + function render_panel() { + var chartData; + var colors = []; + + // IE doesn't work without this + elem.css({height:scope.panel.height||scope.row.height}); + + // Make a clone we can operate on. + + chartData = _.clone(scope.data); + chartData = scope.panel.missing ? chartData : + _.without(chartData,_.findWhere(chartData,{meta:'missing'})); + chartData = scope.panel.other ? chartData : + _.without(chartData,_.findWhere(chartData,{meta:'other'})); + + if (filterSrv.idsByTypeAndField('sankey',scope.panel.field).length > 0) { + colors.push(scope.panel.lastColor); + } else { + colors = scope.panel.chartColors; + } + + var idd = scope.$id; + var echarts = require('echarts'); + + require(['jquery.flot.pie'], function(){ + // Populate element + try { + var labelcolor = false; + if (dashboard.current.style === 'dark'){ + labelcolor = true; + } + // Add plot to scope so we can build out own legend + + + var arrlabel = []; + var sankeydata = []; + var sankey =[]; + + var nodesMap={}; + for (var i = 0; i < chartData.length; i++) { + sankey = chartData[i].label.split("|"); + sankeydata[i]={id:sankey[0],value:sankey[1],number:chartData[i].data[0][1]}; + arrlabel = sankey[0].split(","); + nodesMap[arrlabel[0]]=1; + nodesMap[arrlabel[1]]=1; + + } + //产生nodesæ•°æ® + chartData = null; + + var nodes_data=[]; + + for (var item1 in nodesMap) { + nodes_data.push({ + name:item1 + }); + } + nodesMap = null; + + var links_data = []; + var listMap = {}; + for(var k = 0,key,svalue; k < sankeydata.length; k++){ + key = sankeydata[k].id; + svalue = sankeydata[k].number; + if(scope.panel.sankeymode ==='sum' ){ + svalue = parseInt(sankeydata[k].value); + } + if (!!listMap[key]) { + listMap[key]+=svalue; + } else { + listMap[key] = svalue; + } + } + //产生linksæ•°æ® + sankeydata = null; + + for (var item2 in listMap) { + links_data.push({ + source: item2.split(',')[0], + target: item2.split(',')[1], + value: listMap[item2] + }); + } + + if(nodes_data.length === 0 || typeof(links_data[0].target) === "undefined"){ + + nodes_data=[{"name": "Total"},{"name": "Environment"},{"name": "Land use"},{"name": "Cocoa butter (Organic)"},{"name": "Cocoa mass (Organic)"},{"name": "Hazelnuts (Organic)"},{"name": "Cane sugar (Organic)"},{"name": "Vegetables (Organic)"},{"name": "Climate change"},{"name": "Harmful substances"},{"name": "Water use"},{"name": "Resource depletion"},{"name": "Refrigeration"},{"name": "Packaging"},{"name": "Human rights"},{"name": "Child labour"}, + {"name": "Coconut oil (Organic)"},{"name": "Forced labour"},{"name": "Health safety"},{"name": "Access to water"},{"name": "Freedom of association"},{"name": "Access to land"},{"name": "Sufficient wage"},{"name": "Equal rights migrants"},{"name": "Discrimination"},{"name": "Working hours"}]; + links_data=[{"source": "Total", "target": "Environment", "value": 0.442284047256003},{"source": "Total", "target": "Environment", "value": 0.1},{"source": "Environment", "target": "Land use", "value": 0.32322870366987},{"source": "Land use", "target": "Cocoa butter (Organic)", "value": 0.177682517071359},{"source": "Land use", "target": "Cocoa mass (Organic)", "value": 0.137241325342711}, + {"source": "Land use", "target": "Hazelnuts (Organic)", "value": 0.00433076373512774},{"source": "Land use", "target": "Cane sugar (Organic)", "value": 0.00296956039863467},{"source": "Land use", "target": "Vegetables (Organic)", "value": 0.00100453712203756}, + {"source": "Environment", "target": "Climate change", "value": 0.0112886157414413},{"source": "Climate change", "target": "Cocoa butter (Organic)", "value": 0.00676852971933996},{"source": "Climate change", "target": "Cocoa mass (Organic)", "value": 0.00394686874786743},{"source": "Climate change", "target": "Cane sugar (Organic)", "value": 0.000315972058711838}, + {"source": "Climate change", "target": "Hazelnuts (Organic)", "value": 0.000218969462265292},{"source": "Climate change", "target": "Vegetables (Organic)", "value": 3.82757532567656e-05},{"source": "Environment", "target": "Harmful substances", "value": 0.00604275542495656},{"source": "Harmful substances", "target": "Cocoa mass (Organic)", "value": 0.0055125989240741}, + {"source": "Harmful substances", "target": "Cocoa butter (Organic)", "value": 0.000330017607892127},{"source": "Harmful substances", "target": "Cane sugar (Organic)", "value": 0.000200138892990337}, + {"source": "Harmful substances", "target": "Hazelnuts (Organic)", "value": 0},{"source": "Harmful substances", "target": "Vegetables (Organic)", "value": 0}, + {"source": "Environment", "target": "Water use", "value": 0.00148345269044703}, {"source": "Water use", "target": "Cocoa butter (Organic)", "value": 0.00135309891304186},{"source": "Water use", "target": "Cocoa mass (Organic)", "value": 0.000105714137908639}, + {"source": "Water use", "target": "Hazelnuts (Organic)", "value": 1.33452642581887e-05}, + {"source": "Water use", "target": "Cane sugar (Organic)", "value": 8.78074837009238e-06},{"source": "Water use", "target": "Vegetables (Organic)", "value": 2.5136268682477e-06}, + {"source": "Environment", "target": "Resource depletion", "value": 0.000240519729288764},{"source": "Resource depletion", "target": "Cane sugar (Organic)", "value": 0.000226237279345084}, + {"source": "Resource depletion", "target": "Vegetables (Organic)", "value": 1.42824499436793e-05},{"source": "Resource depletion", "target": "Hazelnuts (Organic)", "value": 0},{"source": "Resource depletion", "target": "Cocoa mass (Organic)", "value": 0},{"source": "Resource depletion", "target": "Cocoa butter (Organic)", "value": 0},{"source": "Environment", "target": "Refrigeration", "value": 0}, + {"source": "Environment", "target": "Packaging", "value": 0},{"source": "Total", "target": "Human rights", "value": 0.307574096993239},{"source": "Human rights", "target": "Child labour", "value": 0.0410641202645833},{"source": "Child labour", "target": "Hazelnuts (Organic)", "value": 0.0105339381639722}, + {"source": "Child labour", "target": "Cocoa mass (Organic)", "value": 0.0105},{"source": "Child labour", "target": "Cocoa butter (Organic)", "value": 0.0087294420777}, + {"source": "Child labour", "target": "Coconut oil (Organic)", "value": 0.00474399974233333},{"source": "Child labour", "target": "Cane sugar (Organic)", "value": 0.00388226450884445}, + {"source": "Child labour", "target": "Vegetables (Organic)", "value": 0.00267447577173333},{"source": "Human rights", "target": "Forced labour", "value": 0.0365458590642445}, + {"source": "Forced labour", "target": "Hazelnuts (Organic)", "value": 0.0114913076376389},{"source": "Forced labour", "target": "Cocoa butter (Organic)", "value": 0.0081134807347}, + {"source": "Forced labour", "target": "Cocoa mass (Organic)", "value": 0.00765230236575}, + {"source": "Forced labour", "target": "Cane sugar (Organic)", "value": 0.004},{"source": "Forced labour", "target": "Vegetables (Organic)", "value": 0.00296668823626667}, + {"source": "Forced labour", "target": "Coconut oil (Organic)", "value": 0.00232208008988889},{"source": "Human rights", "target": "Health safety", "value": 0.0345435327843611}, + {"source": "Health safety", "target": "Hazelnuts (Organic)", "value": 0.0121419536385}, + {"source": "Health safety", "target": "Cocoa mass (Organic)", "value": 0.00766772850678333}, + {"source": "Health safety", "target": "Cocoa butter (Organic)", "value": 0.0056245892061},{"source": "Health safety", "target": "Coconut oil (Organic)", "value": 0.00361616847688889}, + {"source": "Health safety", "target": "Cane sugar (Organic)", "value": 0.00277374682533333},{"source": "Health safety", "target": "Vegetables (Organic)", "value": 0.00271934613075556}, + {"source": "Human rights", "target": "Access to water", "value": 0.0340206659360667}, + {"source": "Access to water", "target": "Cocoa mass (Organic)", "value": 0.0105},{"source": "Access to water", "target": "Cocoa butter (Organic)", "value": 0.0089274160792},{"source": "Access to water", "target": "Hazelnuts (Organic)", "value": 0.0054148022845}, + {"source": "Access to water", "target": "Cane sugar (Organic)", "value": 0.00333938149786667}, + {"source": "Access to water", "target": "Vegetables (Organic)", "value": 0.00314663377488889}, + {"source": "Access to water", "target": "Coconut oil (Organic)", "value": 0.00269243229961111},{"source": "Human rights", "target": "Freedom of association", "value": 0.0320571523941667}, + {"source": "Freedom of association", "target": "Hazelnuts (Organic)", "value": 0.0132312483463611},{"source": "Freedom of association", "target": "Cocoa butter (Organic)", "value": 0.0077695200707}, + {"source": "Freedom of association", "target": "Cocoa mass (Organic)", "value": 0.00510606573995},{"source": "Freedom of association", "target": "Vegetables (Organic)", "value": 0.00354321156324444}, + {"source": "Freedom of association", "target": "Cane sugar (Organic)", "value": 0.00240710667391111}, + {"source": "Freedom of association", "target": "Coconut oil (Organic)", "value": 0}, + {"source": "Human rights", "target": "Access to land", "value": 0.0315022209894056}, + {"source": "Access to land", "target": "Hazelnuts (Organic)", "value": 0.00964970063322223},{"source": "Access to land", "target": "Cocoa mass (Organic)", "value": 0.00938530207965},{"source": "Access to land", "target": "Cocoa butter (Organic)", "value": 0.0060110791848}, + {"source": "Access to land", "target": "Cane sugar (Organic)", "value": 0.00380818314608889}, + {"source": "Access to land", "target": "Vegetables (Organic)", "value": 0.00264795594564445}, + {"source": "Access to land", "target": "Coconut oil (Organic)", "value": 0}, + {"source": "Human rights", "target": "Sufficient wage", "value": 0.0287776757227333}, + {"source": "Sufficient wage", "target": "Cocoa mass (Organic)", "value": 0.00883512456493333}, + {"source": "Sufficient wage", "target": "Cocoa butter (Organic)", "value": 0.0078343367268},{"source": "Sufficient wage", "target": "Coconut oil (Organic)", "value": 0.00347879026511111},{"source": "Sufficient wage", "target": "Hazelnuts (Organic)", "value": 0.00316254211388889},{"source": "Sufficient wage", "target": "Vegetables (Organic)", "value": 0.00281013722808889}, + {"source": "Sufficient wage", "target": "Cane sugar (Organic)", "value": 0.00265674482391111}, + {"source": "Human rights", "target": "Equal rights migrants", "value" : 0.0271146645119444},{"source": "Equal rights migrants", "target": "Cocoa butter (Organic)", "value": 0.0071042315061}, + {"source": "Equal rights migrants", "target": "Cocoa mass (Organic)", "value": 0.00636673210005}, + {"source": "Equal rights migrants", "target": "Hazelnuts (Organic)", "value": 0.00601459775836111}, + {"source": "Equal rights migrants", "target": "Coconut oil (Organic)", "value": 0.00429185583138889}, + {"source": "Equal rights migrants", "target": "Cane sugar (Organic)", "value": 0.00182647471915556},{"source": "Equal rights migrants", "target": "Vegetables (Organic)", "value": 0.00151077259688889},{"source": "Human rights", "target": "Discrimination", "value": 0.0211217763359833},{"source": "Discrimination", "target": "Cocoa mass (Organic)", "value": 0.00609671700306667},{"source": "Discrimination", "target": "Cocoa butter (Organic)", "value": 0.0047738806325},{"source": "Discrimination", "target": "Coconut oil (Organic)", "value": 0.00368119084494444},{"source": "Discrimination", "target": "Vegetables (Organic)", "value": 0.00286009813604444},{"source": "Discrimination", "target": "Cane sugar (Organic)", "value": 0.00283706180951111}, + {"source": "Discrimination", "target": "Hazelnuts (Organic)", "value": 0.000872827909916666},{"source": "Human rights", "target": "Working hours", "value": 0.02082642898975},{"source": "Working hours", "target": "Hazelnuts (Organic)", "value": 0.0107216773848333},{"source": "Working hours", "target": "Coconut oil (Organic)", "value": 0.00359009052944444},{"source": "Working hours", "target": "Vegetables (Organic)", "value": 0.00212300379075556},{"source": "Working hours", "target": "Cocoa butter (Organic)", "value": 0.0018518584356},{"source": "Working hours", "target": "Cocoa mass (Organic)", "value": 0.00158227069058333},{"source": "Working hours", "target": "Cane sugar (Organic)", "value": 0.000957528158533333}]; + + } + if(scope.panel.chart === 'sankey'){ + var myChart = echarts.init(document.getElementById(idd)); + var option = { + + tooltip: { + trigger: 'item', + triggerOn: 'mousemove' + }, + + series: [ + { + + color:colors, + type: 'sankey', + layout: 'none', + label:{ + normal:{ + textStyle:{ + color:'#FFFAFA' + } + } + }, + data: nodes_data, + links: links_data, + itemStyle: { + normal: { + borderWidth: 1, + borderColor: '#aaa' + } + }, + lineStyle: { + normal: { + color:'#88bee7', + curveness: 0.5 + } + } + } + ] +}; + + //if(chartData.length==0){ + //myChart.setOption(option_nodata);}else{ + // myChart.setOption(option); + //} + myChart.setOption(option); + + } + + + + + + // Populate legend + if(elem.is(":visible")){ + setTimeout(function(){ + // scope.legend = plot.getData(); + if(!scope.$$phase) { + scope.$apply(); + } + }); + } + + } catch(e) { + elem.text(e); + } + }); + } + + elem.bind("plotclick", function (event, pos, object) { + if(object) { + scope.build_search(scope.data[object.seriesIndex]); + scope.panel.lastColor = object.series.color; + } + }); + + var $tooltip = $('
'); + elem.bind("plothover", function (event, pos, item) { + if (item) { + var value = scope.panel.chart === 'bar' ? item.datapoint[1] : item.datapoint[1][0][1]; + // if (scope.panel.mode === 'count') { + // value = value.toFixed(0); + // } else { + // value = value.toFixed(scope.panel.decimal_points); + // } + $tooltip + .html( + kbn.query_color_dot(item.series.color, 20) + ' ' + + item.series.label + " (" + dashboard.numberWithCommas(value.toFixed(scope.panel.decimal_points)) +")" + ) + .place_tt(pos.pageX, pos.pageY); + } else { + $tooltip.remove(); + } + }); + + } + }; + }); + +}); diff --git a/src/app/panels/scatterplot/editor.html b/src/app/panels/scatterplot/editor.html index 0b393195e..898580aa7 100644 --- a/src/app/panels/scatterplot/editor.html +++ b/src/app/panels/scatterplot/editor.html @@ -1,72 +1,25 @@
- Specify which fields to be plotted on X-axis and Y-axis. Both fields have to be numeric. - You can also specify custom labels for X and Y axes (optional). - The specified field in Color Field will be grouped by its values with different colors. - The specified field in Bubble Size Field has to be numeric field, and its values will affect the bubble size in the chart. - The larger the value, the bigger the bubble. +
+
X-axis Must be numeric field
+ +
+
+
Y-axis Must be numeric field
+ +
+
+
Category field the colors in the plot will be divided according to this field
+ +
+
+
Max Rows
+ +
- -
-
-
X-axis Field - Must be a numeric field. -
- -
-
-
X-axis Label
- -
-
- -
-
-
Y-axis Field - Must be a numeric field. -
- -
-
-
Y-axis Label
- -
-
-
-
-
Color Field - The color in the plot will be generated according to this field. -
- -
-
-
Bubble Size Field - Must be a numeric field. -
- -
-
-
Max Rows
- -
-
+
Linkage Effective
+
+ +
-
-
Real-time (Auto-refresh)
-
- -
-
- - -
-
+
\ No newline at end of file diff --git a/src/app/panels/scatterplot/module.html b/src/app/panels/scatterplot/module.html index 5b4cd5e05..1dc666c2b 100644 --- a/src/app/panels/scatterplot/module.html +++ b/src/app/panels/scatterplot/module.html @@ -1,46 +1,40 @@
- +
+ +
diff --git a/src/app/panels/scatterplot/module.js b/src/app/panels/scatterplot/module.js index b82df165e..97fbaa6f3 100644 --- a/src/app/panels/scatterplot/module.js +++ b/src/app/panels/scatterplot/module.js @@ -1,34 +1,29 @@ /* - ## Scatterplot Panel + ## Multiseries Panel - */ +*/ define([ 'angular', 'app', 'underscore', 'jquery', 'd3', -], function (angular, app, _, $, d3) { +], function(angular, app, _, $, d3) { 'use strict'; var module = angular.module('kibana.panels.scatterplot', []); app.useModule(module); - module.controller('scatterplot', function ($scope, $timeout, timer, dashboard, querySrv, filterSrv) { + module.controller('scatterplot', function($scope, dashboard, querySrv, filterSrv) { $scope.panelMeta = { - modals: [{ - description: "Inspect", - icon: "icon-info-sign", - partial: "app/partials/inspector.html", - show: $scope.panel.spyable - }], + editorTabs: [{ title: 'Queries', src: 'app/partials/querySelect.html' }], - status: "Stable", - description: "This panel helps you to plot a bubble scatterplot between two to four variables." + status: "Experimental", + description: "This panel help user to plot scatter plot between two variables" }; // default values @@ -36,62 +31,34 @@ define([ queries: { mode: 'all', ids: [], + display:'block', + icon:"icon-caret-down", query: '*:*', custom: '' }, max_rows: 1000, // maximum number of rows returned from Solr - xaxis: '', - yaxis: '', - xaxisLabel: '', - yaxisLabel: '', - colorField: '', - bubbleSizeField: '', + field: 'date', + xAxis: 'Date', + yAxis: 'Rates', + linkage_id:'a', + fl: 'open,high,low,close', + rightAxis: 'volume', // TODO: need to remove hard coded field (volume). spyable: true, - show_queries: true, - refresh: { - enable: false, - interval: 2 - } + show_queries:true, }; _.defaults($scope.panel, _d); - $scope.init = function () { - // Start refresh timer if enabled - if ($scope.panel.refresh.enable) { - $scope.set_timer($scope.panel.refresh.interval); - } - $scope.$on('refresh', function () { + $scope.init = function() { + $scope.$on('refresh', function() { $scope.get_data(); }); $scope.get_data(); }; - $scope.set_timer = function (refresh_interval) { - $scope.panel.refresh.interval = refresh_interval; - if (_.isNumber($scope.panel.refresh.interval)) { - timer.cancel($scope.refresh_timer); - $scope.realtime(); - } else { - timer.cancel($scope.refresh_timer); - } - }; - - $scope.realtime = function () { - if ($scope.panel.refresh.enable) { - timer.cancel($scope.refresh_timer); - - $scope.refresh_timer = timer.register($timeout(function () { - $scope.realtime(); - $scope.get_data(); - }, $scope.panel.refresh.interval * 1000)); - } else { - timer.cancel($scope.refresh_timer); - } - }; - - $scope.get_data = function () { + $scope.get_data = function() { + if(($scope.panel.linkage_id === dashboard.current.linkage_id)||dashboard.current.enable_linkage){ // Show progress by displaying a spinning wheel icon on panel $scope.panelMeta.loading = true; delete $scope.panel.error; @@ -99,7 +66,6 @@ define([ var request, results; // Set Solr server $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); - // -------------------- TODO: REMOVE ALL ELASTIC SEARCH AFTER FIXING SOLRJS -------------- $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); // This could probably be changed to a BoolFilter @@ -123,16 +89,9 @@ define([ fq = '&' + filterSrv.getSolrFq(); } var wt_json = '&wt=csv'; + var fl = '&fl=' + $scope.panel.xaxis + ',' + $scope.panel.yaxis + ',' + $scope.panel.field_type; var rows_limit = '&rows=' + $scope.panel.max_rows; - var fl = '&fl=' + $scope.panel.xaxis + ',' + $scope.panel.yaxis; - - if ($scope.panel.colorField) { - fl += ',' + $scope.panel.colorField; - } - - if ($scope.panel.bubbleSizeField) { - fl += ',' + $scope.panel.bubbleSizeField; - } + //var sort = '&sort=' + $scope.panel.field + ' asc'; $scope.panel.queries.query = querySrv.getORquery() + fq + fl + wt_json + rows_limit; @@ -149,43 +108,37 @@ define([ // Populate scope when we have results results.then(function (results) { // build $scope.data array - $scope.data = d3.csv.parse(results, function (d) { - var value = {}; - // Convert string to number - value[$scope.panel.xaxis] = +d[$scope.panel.xaxis]; - value[$scope.panel.yaxis] = +d[$scope.panel.yaxis]; - if ($scope.panel.colorField) { - value[$scope.panel.colorField] = d[$scope.panel.colorField]; - } - if ($scope.panel.bubbleSizeField) { - value[$scope.panel.bubbleSizeField] = +d[$scope.panel.bubbleSizeField]; - } - - return value; - }, function(error, rows) { - console.log('Error parsing results from Solr: ', rows); - }); - - if ($scope.data.length === 0) { + //$scope.data = results.response.docs; + $scope.data = d3.csv.parse(results); + if (!$scope.data.length) { $scope.panel.error = $scope.parse_error("There's no data to show"); } - + // $scope.data = results; $scope.render(); }); // Hide the spinning wheel icon $scope.panelMeta.loading = false; + } }; - $scope.set_refresh = function (state) { + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; + + $scope.set_refresh = function(state) { $scope.refresh = state; }; - $scope.close_edit = function () { - // Start refresh timer if enabled - if ($scope.panel.refresh.enable) { - $scope.set_timer($scope.panel.refresh.interval); - } + $scope.close_edit = function() { if ($scope.refresh) { $scope.get_data(); } @@ -193,213 +146,162 @@ define([ $scope.$emit('render'); }; - $scope.render = function () { + $scope.render = function() { $scope.$emit('render'); }; - $scope.populate_modal = function (request) { + $scope.populate_modal = function(request) { $scope.inspector = angular.toJson(JSON.parse(request.toString()), true); }; - $scope.pad = function (n) { + $scope.pad = function(n) { return (n < 10 ? '0' : '') + n; }; + }); - module.directive('scatterplot', function (dashboard, filterSrv) { + module.directive('scatterplot', function() { return { restrict: 'E', - link: function (scope, element) { + link: function(scope, element) { - scope.$on('render', function () { + scope.$on('render', function() { render_panel(); }); - angular.element(window).bind('resize', function () { + angular.element(window).bind('resize', function() { render_panel(); }); // Function for rendering panel function render_panel() { element.html(""); + var el = element[0]; + var parent_width = element.parent().width(), height = parseInt(scope.row.height), padding = 50; + var margin = { - top: 20, - right: 20, - bottom: 100, - left: 50 - }, - width = parent_width - margin.left - margin.right; + top: 20, + right: 20, + bottom: 100, + left: 50 + }, + width = parent_width - margin.left - margin.right; height = height - margin.top - margin.bottom; - // Scales - var color = d3.scale.category20(); - var rScale; - if (scope.panel.bubbleSizeField) { - rScale = d3.scale.linear() - .domain(d3.extent(scope.data, function (d) { - return d[scope.panel.bubbleSizeField]; - })) - .range([3, 20]) - .nice(); - } var x = d3.scale.linear() .range([0, width - padding * 2]); + var y = d3.scale.linear() .range([height, 0]); - x.domain(d3.extent(scope.data, function (d) { - return d[scope.panel.xaxis]; - })).nice(); + var color = d3.scale.category10(); - y.domain(d3.extent(scope.data, function (d) { - return d[scope.panel.yaxis]; - })).nice(); + var xAxis = d3.svg.axis() + .scale(x) + .orient("bottom"); + + var yAxis = d3.svg.axis() + .scale(y) + .orient("left"); var svg = d3.select(el).append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) - .attr("viewBox", "0 0 " + parent_width + " " + (height + margin.top + margin.bottom)) + .attr("viewBox", "0 0 " + parent_width + " " + (height + margin.top)) .attr("preserveAspectRatio", "xMidYMid") .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); - // add the tooltip area to the webpage var $tooltip = $('
'); - // Bubble + scope.data.forEach(function(d) { + d[scope.panel.yaxis] = +d[scope.panel.yaxis]; + d[scope.panel.xaxis] = +d[scope.panel.xaxis]; + }); + + x.domain(d3.extent(scope.data, function(d) { + return d[scope.panel.xaxis]; + })).nice(); + y.domain(d3.extent(scope.data, function(d) { + return d[scope.panel.yaxis]; + })).nice(); + + svg.append("g") + .attr("class", "x axis") + .attr("transform", "translate(0," + height + ")") + .call(xAxis) + .append("text") + .attr("class", "label") + .attr("transform", "translate(" + ((width / 2) - margin.left) + " ," + 30+ ")") + .style("text-anchor", "middle") + .text(scope.panel.xaxis); + + svg.append("g") + .attr("class", "y axis") + .call(yAxis) + .append("text") + .attr("class", "label") + .attr("transform", "rotate(-90)") + .attr("y", 0 - margin.left) + .attr("x",0 - ((height-margin.top-margin.bottom) / 2)) + .attr("dy", ".71em") + .style("text-anchor", "end") + .text(scope.panel.yaxis); + svg.selectAll(".dot") .data(scope.data) .enter().append("circle") .attr("class", "dot") - .attr("r", function (d) { - if (scope.panel.bubbleSizeField) { - return rScale(d[scope.panel.bubbleSizeField]); - } else { - return 3; - } - }) - .attr("cx", function (d) { + .attr("r", 3.5) + .attr("cx", function(d) { return x(d[scope.panel.xaxis]); }) - .attr("cy", function (d) { + .attr("cy", function(d) { return y(d[scope.panel.yaxis]); }) - .style("fill", function (d) { - return color(d[scope.panel.colorField]); - }) - .on("mouseover", function (d) { - var colorField = d[scope.panel.colorField] ? d[scope.panel.colorField] : ""; + .style("fill", function(d) { + return color(d[scope.panel.field_type]); + }).on("mouseover", function(d) { + var field_type = d[scope.panel.field_type] ? d[scope.panel.field_type] : ""; $tooltip - .html('' + ' ' + - colorField + " (" + d[scope.panel.xaxis] + ", " + d[scope.panel.yaxis] + ")
") + .html('' + ' ' + + field_type + " (" + d[scope.panel.xaxis] + ", " + d[scope.panel.yaxis] + ")
") .place_tt(d3.event.pageX, d3.event.pageY); }) - .on("mouseout", function () { + .on("mouseout", function() { $tooltip.detach(); - }) - .on("click", function (d) { - if (scope.panel.colorField) { - filterSrv.set({ - type: 'terms', - field: scope.panel.colorField, - value: d[scope.panel.colorField], - mandate: 'must' - }); - $tooltip.detach(); - dashboard.refresh(); - } }); - - if (scope.panel.colorField) { + if (scope.panel.field_type) { var legend = svg.selectAll(".legend") .data(color.domain()) .enter().append("g") .attr("class", "legend") - .attr("transform", function (d, i) { + .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; - }) - .on("mouseover", function () { - el.style.cursor = 'pointer'; - }) - .on("mouseout", function () { - el.style.cursor = 'auto'; - }) - .on("click", function (d) { - filterSrv.set({ - type: 'terms', - field: scope.panel.colorField, - value: d, - mandate: 'must' - }); - - el.style.cursor = 'auto'; - dashboard.refresh(); }); legend.append("text") .attr("x", width - 24) .attr("y", 9) .attr("dy", ".35em") .style("text-anchor", "end") - .text(function (d) { + .text(function(d) { return d; }); + legend.append("rect") .attr("x", width - 18) .attr("width", 18) .attr("height", 18) .style("fill", color); - } - // Axis - var xAxis = d3.svg.axis() - .scale(x) - .orient("bottom"); - var yAxis = d3.svg.axis() - .scale(y) - .orient("left"); - // X-axis label - var xaxisLabel = ''; - if (scope.panel.xaxisLabel) { - xaxisLabel = scope.panel.xaxisLabel; - } else { - xaxisLabel = scope.panel.xaxis; } - svg.append("g") - .attr("class", "x axis") - .attr("transform", "translate(0," + height + ")") - .call(xAxis) - .append("text") - .attr("class", "label") - .attr("transform", "translate(" + ((width / 2) - margin.left) + " ," + 30 + ")") - .style("text-anchor", "middle") - .text(xaxisLabel); - - // Y-axis label - var yaxisLabel = ''; - if (scope.panel.yaxisLabel) { - yaxisLabel = scope.panel.yaxisLabel; - } else { - yaxisLabel = scope.panel.yaxis; - } - - svg.append("g") - .attr("class", "y axis") - .call(yAxis) - .append("text") - .attr("class", "label") - .attr("transform", "rotate(-90)") - .attr("y", 0 - margin.left) - .attr("x", 0 - ((height - margin.top - margin.bottom) / 2)) - .attr("dy", ".71em") - .style("text-anchor", "end") - .text(yaxisLabel); } } }; diff --git a/src/app/panels/search/editor.html b/src/app/panels/search/editor.html new file mode 100644 index 000000000..cdf334a61 --- /dev/null +++ b/src/app/panels/search/editor.html @@ -0,0 +1,12 @@ +
+ + +
+
Linkage Effective
+
+ +
+ + diff --git a/src/app/panels/search/meta.html b/src/app/panels/search/meta.html new file mode 100644 index 000000000..9640db179 --- /dev/null +++ b/src/app/panels/search/meta.html @@ -0,0 +1,21 @@ +
+ + + × + + +
+ +
+ +
+
+
\ No newline at end of file diff --git a/src/app/panels/search/module.html b/src/app/panels/search/module.html new file mode 100644 index 000000000..04d5e004f --- /dev/null +++ b/src/app/panels/search/module.html @@ -0,0 +1,29 @@ +
+
+ + + + + +
+
diff --git a/src/app/panels/search/module.js b/src/app/panels/search/module.js new file mode 100644 index 000000000..631e4c7af --- /dev/null +++ b/src/app/panels/search/module.js @@ -0,0 +1,107 @@ +/* + + ## query + + ### Parameters + * query :: A string or an array of querys. String if multi is off, array if it is on + This should be fixed, it should always be an array even if its only + one element +*/ +define([ + 'angular', + 'app', + 'underscore', + 'css!./query.css' +], function (angular, app, _) { + 'use strict'; + + var module = angular.module('kibana.panels.query', []); + app.useModule(module); + + module.controller('search', function($scope, querySrv,filterSrv, dashboard,$rootScope) { + $scope.panelMeta = { + + status : "Stable", + description : "Provide a search bar for free-form queries. You almost certainly want one of these somewhere prominent on your dashboard." + }; + + // Set and populate defaults + var _d = { + query : "*:*", + pinned : true, + linkage_id:'a', + display:'block', + icon:"icon-caret-down", + search:"*:*", + history : [], + spyable : true, + remember: 10, // max: 100, angular strap can't take a variable for items param + }; + _.defaults($scope.panel,_d); + + $scope.querySrv = querySrv; + + $scope.init = function() { + }; + + $scope.refresh = function() { + dashboard.current.linkage_id = $scope.panel.linkage_id; + dashboard.current.enable_linkage = false; + update_history(_.pluck($scope.querySrv.list,'query')); + $rootScope.$broadcast('refresh'); + }; + + $scope.render = function() { + $rootScope.$broadcast('render'); + }; + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; + + $scope.build_search = function() { + if( dashboard.current.isSearch){ + filterSrv.remove(dashboard.current.searchID);} + dashboard.current.searchEnable = true; + var searchList = []; + searchList = $scope.panel.search.split(":"); + filterSrv.set({ + type: 'querystring', field: searchList[0], value:searchList[1], query: $scope.panel.search, + mandate: ('must') + }); + + dashboard.current.linkage_id = $scope.panel.linkage_id; + dashboard.current.enable_linkage = false; + dashboard.current.isSearch = true; + dashboard.refresh(); + + }; + + $scope.toggle_pin = function(id) { + querySrv.list[id].pin = querySrv.list[id].pin ? false : true; + }; + + $scope.close_edit = function() { + $scope.refresh(); + }; + + var update_history = function(query) { + if($scope.panel.remember > 0) { + $scope.panel.history = _.union(query.reverse(),$scope.panel.history); + var _length = $scope.panel.history.length; + if(_length > $scope.panel.remember) { + $scope.panel.history = $scope.panel.history.slice(0,$scope.panel.remember); + } + } + }; + + $scope.init(); + }); +}); diff --git a/src/app/panels/search/query.css b/src/app/panels/search/query.css new file mode 100644 index 000000000..7f3182823 --- /dev/null +++ b/src/app/panels/search/query.css @@ -0,0 +1,39 @@ +.short-query { + display:inline-block; + margin-right: 10px; +} +.begin-query { + position:absolute; + left:13px; + top:5px; +} +.end-query { + position:absolute; + right:15px; + top:5px; +} +.panel-query { + padding-left: 35px !important; + height: 31px !important; + -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */ + -moz-box-sizing: border-box; /* Firefox, other Gecko */ + box-sizing: border-box; /* Opera/IE 8+ */ +} +.form-search:hover .has-remove { + padding-left: 50px !important; +} +.remove-query { + opacity: 0; +} +.last-query { + padding-right: 45px !important; +} +.form-search:hover .remove-query { + opacity: 1; +} +.query-panel .pins { + text-decoration: underline; +} +.query-panel .pinned { + margin-right: 5px; +} \ No newline at end of file diff --git a/src/app/panels/simplegram/editor.html b/src/app/panels/simplegram/editor.html new file mode 100644 index 000000000..b717da17b --- /dev/null +++ b/src/app/panels/simplegram/editor.html @@ -0,0 +1,135 @@ +
+
+ + + + +
+
+ + +
+
+ + +
+
+ In {{panel.mode}} mode the configured field must be a numeric type. +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+ +
+ +
Chart Settings
+
+
+
+
+
+
+ + +
+
+
+
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ + +
+
+ +
Tooltip Settings
+
+
+ + +
+
+ + +
+
+
+
Linkage Effective
+
+ +
+ +
+ diff --git a/src/app/panels/simplegram/interval.js b/src/app/panels/simplegram/interval.js new file mode 100644 index 000000000..673371fcf --- /dev/null +++ b/src/app/panels/simplegram/interval.js @@ -0,0 +1,57 @@ +define([ + 'kbn' +], +function (kbn) { + 'use strict'; + + /** + * manages the interval logic + * @param {[type]} interval_string An interval string in the format '1m', '1y', etc + */ + function Interval(interval_string) { + this.string = interval_string; + + var info = kbn.describe_interval(interval_string); + this.type = info.type; + this.ms = info.sec * 1000 * info.count; + + // does the length of the interval change based on the current time? + if (this.type === 'y' || this.type === 'M') { + // we will just modify this time object rather that create a new one constantly + this.get = this.get_complex; + this.date = new Date(0); + } else { + this.get = this.get_simple; + } + } + + Interval.prototype = { + toString: function () { + return this.string; + }, + after: function(current_ms) { + return this.get(current_ms, 1); + }, + before: function (current_ms) { + return this.get(current_ms, -1); + }, + get_complex: function (current, delta) { + this.date.setTime(current); + switch(this.type) { + case 'M': + this.date.setUTCMonth(this.date.getUTCMonth() + delta); + break; + case 'y': + this.date.setUTCFullYear(this.date.getUTCFullYear() + delta); + break; + } + return this.date.getTime(); + }, + get_simple: function (current, delta) { + return current + (delta * this.ms); + } + }; + + return Interval; + +}); \ No newline at end of file diff --git a/src/app/panels/simplegram/module.html b/src/app/panels/simplegram/module.html new file mode 100644 index 000000000..c38e5f297 --- /dev/null +++ b/src/app/panels/simplegram/module.html @@ -0,0 +1,96 @@ +
+ +
+
+ + + View + |  + + + + Zoom Out |  + + + + {{series.info.alias}} + + +
+
+ + + + + + + + + + + + + +
+ +
+
+ + + +
+
+
+
+
diff --git a/src/app/panels/simplegram/module.js b/src/app/panels/simplegram/module.js new file mode 100644 index 000000000..f0f939c91 --- /dev/null +++ b/src/app/panels/simplegram/module.js @@ -0,0 +1,833 @@ +/* + + ## Histogram + + ### Parameters + * auto_int :: Auto calculate data point interval? + * resolution :: If auto_int is enables, shoot for this many data points, rounding to + sane intervals + * interval :: Datapoint interval in elasticsearch date math format (eg 1d, 1w, 1y, 5y) + * fill :: Only applies to line charts. Level of area shading from 0-10 + * linewidth :: Only applies to line charts. How thick the line should be in pixels + While the editor only exposes 0-10, this can be any numeric value. + Set to 0 and you'll get something like a scatter plot + * timezone :: This isn't totally functional yet. Currently only supports browser and utc. + browser will adjust the x-axis labels to match the timezone of the user's + browser + * spyable :: Dislay the 'eye' icon that show the last elasticsearch query + * zoomlinks :: Show the zoom links? + * bars :: Show bars in the chart + * stack :: Stack multiple queries. This generally a crappy way to represent things. + You probably should just use a line chart without stacking + * points :: Should circles at the data points on the chart + * lines :: Line chart? Sweet. + * legend :: Show the legend? + * x-axis :: Show x-axis labels and grid lines + * y-axis :: Show y-axis labels and grid lines + * interactive :: Allow drag to select time range + +*/ +define([ + 'angular', + 'app', + 'jquery', + 'underscore', + 'kbn', + 'moment', + './timeSeries', + + 'jquery.flot', + 'jquery.flot.pie', + 'jquery.flot.selection', + 'jquery.flot.time', + 'jquery.flot.stack', + 'jquery.flot.stackpercent', + 'jquery.flot.axislabels' +], +function (angular, app, $, _, kbn, moment, timeSeries) { + 'use strict'; + + var module = angular.module('kibana.panels.simplegram', []); + app.useModule(module); + + module.controller('simplegram', function($scope, $q, querySrv, dashboard, filterSrv) { + $scope.panelMeta = { + + editorTabs : [ + { + title:'Queries', + src:'app/partials/querySelect.html' + } + ], + status : "Stable", + description : "A bucketed time series chart of the current query, including all applied time and non-time filters, when used in count mode. Uses Solr’s facet.range query parameters. In values mode, it plots the value of a specific field over time, and allows the user to group field values by a second field." + }; + + // Set and populate defaults + var _d = { + mode : 'count', + queries : { + mode : 'all', + ids : [], + query : '*:*', + custom : '' + }, + max_rows : 100000, // maximum number of rows returned from Solr (also use this for group.limit to simplify UI setting) + reverse :0, + segment :3, + display:'block', + icon:"icon-caret-down", + threshold_first:1000, + threshold_second:2000, + threshold_third:3000, + value_field : null, + group_field : null, + auto_int : true, + resolution : 100, + interval : '5m', + intervals : ['auto','1s','1m','5m','10m','30m','1h','3h','12h','1d','1w','1M','1y'], + fill : 0, + linewidth : 3, + timezone : 'browser', // browser, utc or a standard timezone + spyable : true, + zoomlinks : true, + bars : true, + linkage_id:'a', + stack : true, + points : false, + lines : false, + lines_smooth: false, // Enable 'smooth line' mode by removing zero values from the plot. + legend : true, + 'x-axis' : true, + 'y-axis' : true, + percentage : false, + interactive : true, + options : true, + show_queries:true, + tooltip : { + value_type: 'cumulative', + query_as_alias: false + } + }; + + _.defaults($scope.panel,_d); + + $scope.init = function() { + // Hide view options by default + $scope.options = false; + $scope.$on('refresh',function(){ + $scope.get_data(); + }); + + $scope.get_data(); + + }; + + $scope.set_interval = function(interval) { + if(interval !== 'auto') { + $scope.panel.auto_int = false; + $scope.panel.interval = interval; + } else { + $scope.panel.auto_int = true; + } + }; + + $scope.interval_label = function(interval) { + return $scope.panel.auto_int && interval === $scope.panel.interval ? interval+" (auto)" : interval; + }; + + /** + * The time range effecting the panel + * @return {[type]} [description] + */ + $scope.get_time_range = function () { + var range = $scope.range = filterSrv.timeRange('min'); + return range; + }; + + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; + + $scope.get_interval = function () { + var interval = $scope.panel.interval, + range; + if ($scope.panel.auto_int) { + range = $scope.get_time_range(); + if (range) { + interval = kbn.secondsToHms( + kbn.calculate_interval(range.from, range.to, $scope.panel.resolution, 0) / 1000 + ); + } + } + $scope.panel.interval = interval || '10m'; + return $scope.panel.interval; + }; + + /** + * Fetch the data for a chunk of a queries results. Multiple segments occur when several indicies + * need to be consulted (like timestamped logstash indicies) + * + * The results of this function are stored on the scope's data property. This property will be an + * array of objects with the properties info, time_series, and hits. These objects are used in the + * render_panel function to create the historgram. + * + * !!! Solr does not need to fetch the data in chunk because it uses a facet search and retrieve + * !!! all events from a single query. + * + * @param {number} segment The segment count, (0 based) + * @param {number} query_id The id of the query, generated on the first run and passed back when + * this call is made recursively for more segments + */ + $scope.get_data = function(segment, query_id) { + if(($scope.panel.linkage_id === dashboard.current.linkage_id)||dashboard.current.enable_linkage){ + if (_.isUndefined(segment)) { + segment = 0; + } + delete $scope.panel.error; + + // Make sure we have everything for the request to complete + if (dashboard.indices.length === 0) { + return; + } + var _range = $scope.get_time_range(); + var _interval = $scope.get_interval(_range); + + if ($scope.panel.auto_int) { + $scope.panel.interval = kbn.secondsToHms( + kbn.calculate_interval(_range.from, _range.to, $scope.panel.resolution, 0) / 1000); + } + + $scope.panelMeta.loading = true; + + // Solr + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + var request = $scope.sjs.Request().indices(dashboard.indices[segment]); + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + + + $scope.panel.queries.query = ""; + // Build the query + _.each($scope.panel.queries.ids, function (id) { + var query = $scope.sjs.FilteredQuery( + querySrv.getEjsObj(id), + filterSrv.getBoolFilter(filterSrv.ids) + ); + + var facet = $scope.sjs.DateHistogramFacet(id); + if ($scope.panel.mode === 'count' || $scope.panel.mode === 'counts') { + facet = facet.field(filterSrv.getTimeField()); + } else { + if (_.isNull($scope.panel.value_field)) { + $scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified"; + return; + } + facet = facet.keyField(filterSrv.getTimeField()).valueField($scope.panel.value_field); + } + facet = facet.interval(_interval).facetFilter($scope.sjs.QueryFilter(query)); + request = request.facet(facet).size(0); + + }); + + // Populate the inspector panel + $scope.populate_modal(request); + + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + } + var time_field = filterSrv.getTimeField(); + var start_time = filterSrv.getStartTime(); + var end_time = filterSrv.getEndTime(); + + // facet.range.end does NOT accept * as a value, need to convert it to NOW + if (end_time === '*') { + end_time = 'NOW'; + } + + var wt_json = '&wt=json'; + var rows_limit = '&rows=0'; // for histogram, we do not need the actual response doc, so set rows=0 + var facet_gap = $scope.sjs.convertFacetGap($scope.panel.interval); + var facet = '&facet=true' + + '&facet.range=' + time_field + + '&facet.range.start=' + start_time + + '&facet.range.end=' + end_time + + '&facet.range.gap=' + facet_gap; + var values_mode_query = ''; + + // For mode = value + if ($scope.panel.mode === 'values' || $scope.panel.mode === 'value') { + if (!$scope.panel.value_field) { + $scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified"; + return; + } + + values_mode_query = '&fl=' + time_field + ' ' + $scope.panel.value_field; + rows_limit = '&rows=' + $scope.panel.max_rows; + facet = ''; + + // if Group By Field is specified + if ($scope.panel.group_field) { + values_mode_query += '&group=true&group.field=' + $scope.panel.group_field + '&group.limit=' + $scope.panel.max_rows; + } + } + + var mypromises = []; + + var arr_id = [0]; + + + _.each(arr_id, function (id) { + var temp_q = querySrv.getQuery(id) + wt_json + rows_limit + fq + facet + values_mode_query; + + $scope.panel.queries.query += temp_q + "\n"; + if ($scope.panel.queries.custom !== null) { + request = request.setQuery(temp_q + $scope.panel.queries.custom); + } else { + request = request.setQuery(temp_q); + } + mypromises.push(request.doSearch()); + }); + + + if (dashboard.current.services.query.ids.length >= 1) { + $q.all(mypromises).then(function (results) { + $scope.panelMeta.loading = false; + if (segment === 0) { + $scope.hits = 0; + $scope.data = []; + query_id = $scope.query_id = new Date().getTime(); + } + // Convert facet ids to numbers + // var facetIds = _.map(_.keys(results.facets),function(k){return parseInt(k, 10);}); + //var facetIds = [0]; // Need to fix this + + // Make sure we're still on the same query/queries + // TODO: We probably DON'T NEED THIS unless we have to support multiple queries in query module. + // if ($scope.query_id === query_id && _.difference(facetIds, $scope.panel.queries.ids).length === 0) { + var i = 0, + time_series, + hits; + + _.each(arr_id, function (id, index) { + // Check for error and abort if found + if (!(_.isUndefined(results[index].error))) { + $scope.panel.error = $scope.parse_error(results[index].error.msg); + return; + } + // we need to initialize the data variable on the first run, + // and when we are working on the first segment of the data. + if (_.isUndefined($scope.data[i]) || segment === 0) { + time_series = new timeSeries.ZeroFilled({ + interval: _interval, + start_date: _range && _range.from, + end_date: _range && _range.to, + fill_style: 'minimal' + }); + hits = 0; + } else { + time_series = $scope.data[i].time_series; + // Bug fix for wrong event count: + // Solr don't need to accumulate hits count since it can get total count from facet query. + // Therefore, I need to set hits and $scope.hits to zero. + // hits = $scope.data[i].hits; + hits = 0; + $scope.hits = 0; + } + + // Solr facet counts response is in one big array. + // So no need to get each segment like Elasticsearch does. + var entry_time, entries, entry_value; + if ($scope.panel.mode === 'count' || $scope.panel.mode === 'counts') { + // Entries from facet_ranges counts + entries = results[index].facet_counts.facet_ranges[time_field].counts; + for (var j = 0; j < entries.length; j++) { + entry_time = new Date(entries[j]).getTime(); // convert to millisec + j++; + var entry_count = entries[j]; + var nowTime = new Date().getTime(); + if(entry_time<=nowTime){ + time_series.addValue(entry_time, entry_count); + hits += entry_count; // The series level hits counter + $scope.hits += entry_count; + } + } + } else if ($scope.panel.mode === 'values' || $scope.panel.mode === 'value') { + if ($scope.panel.group_field) { + // Group By Field is specified + var groups = results[index].grouped[$scope.panel.group_field].groups; + + for (var j = 0; j < groups.length; j++) { // jshint ignore: line + var docs = groups[j].doclist.docs; + var group_time_series = new timeSeries.ZeroFilled({ + interval: _interval, + start_date: _range && _range.from, + end_date: _range && _range.to, + fill_style: 'minimal' + }); + hits = 0; + + // loop through each group results + for (var k = 0; k < docs.length; k++) { + entry_time = new Date(docs[k][time_field]).getTime(); // convert to millisec + entry_value = docs[k][$scope.panel.value_field]; + group_time_series.addValue(entry_time, entry_value); + hits += 1; + $scope.hits += 1; + } + + $scope.data[j] = { + // info: querySrv.list[id], + // Need to define chart info here according to the results, cannot use querySrv.list[id] + info: { + alias: groups[j].groupValue, + color: querySrv.colors[j], + + }, + time_series: group_time_series, + hits: hits + }; + } + } else { // Group By Field is not specified + entries = results[index].response.docs; + for (var j = 0; j < entries.length; j++) { // jshint ignore: line + entry_time = new Date(entries[j][time_field]).getTime(); // convert to millisec + entry_value = entries[j][$scope.panel.value_field]; + time_series.addValue(entry_time, entry_value); + hits += 1; + $scope.hits += 1; + } + + $scope.data[i] = { + info: querySrv.list[id], + time_series: time_series, + hits: hits + }; + } + } + + if ($scope.panel.mode !== 'values' || $scope.panel.mode !== 'value') { + $scope.data[i] = { + info: {alias: $scope.panel.value_field, color: "#1a93f9"}, + time_series: time_series, + hits: hits + }; + } + + i++; + }); + + // Tell the histogram directive to render. + $scope.$emit('render'); + // } + }); + } + } + }; + + // function $scope.zoom + // factor :: Zoom factor, so 0.5 = cuts timespan in half, 2 doubles timespan + $scope.zoom = function(factor) { + var _range = filterSrv.timeRange('min'); + var _timespan = (_range.to.valueOf() - _range.from.valueOf()); + var _center = _range.to.valueOf() - _timespan/2; + + var _to = (_center + (_timespan*factor)/2); + var _from = (_center - (_timespan*factor)/2); + + // If we're not already looking into the future, don't. + if(_to > Date.now() && _range.to < Date.now()) { + var _offset = _to - Date.now(); + _from = _from - _offset; + _to = Date.now(); + } + + var time_field = filterSrv.getTimeField(); + if(factor > 1) { + filterSrv.removeByType('time'); + } + + filterSrv.set({ + type:'time', + from:moment.utc(_from).toDate(), + to:moment.utc(_to).toDate(), + field:time_field + }); + + dashboard.refresh(); + }; + + // I really don't like this function, too much dom manip. Break out into directive? + $scope.populate_modal = function(request) { + $scope.inspector = angular.toJson(JSON.parse(request.toString()),true); + }; + + $scope.set_refresh = function (state) { + $scope.refresh = state; + }; + + $scope.close_edit = function() { + if($scope.refresh) { + $scope.get_data(); + } + $scope.refresh = false; + $scope.$emit('render'); + }; + + $scope.render = function() { + $scope.$emit('render'); + }; + + }); + + module.directive('simplegramChart', function($scope, dashboard, filterSrv) { + return { + restrict: 'A', + template: '
', + link: function(scope, elem) { + + // Receive render events + scope.$on('render',function(){ + render_panel(); + }); + + // Re-render if the window is resized + angular.element(window).bind('resize', function(){ + render_panel(); + }); + + // Function for rendering panel + function render_panel() { + // IE doesn't work without this + elem.css({height:scope.panel.height || scope.row.height}); + + // Populate from the query service + //var num_all = 0; + + //_.each(scope.data, function(seri) { + //num_all += seri.hits; + //}); + try { + _.each(scope.data, function(series) { + series.color = series.info.color; + + //series.color = '%'; + //var mid = parseFloat((100*series.hits/num_all).toFixed(2)); + //series.hits = mid; + //series.label ='%'; + + // series.info.alias = series.info.alias+"% " + + + }); + } catch(e) {return;} + + // Set barwidth based on specified interval + var barwidth = kbn.interval_to_ms(scope.panel.interval); + + var stack = scope.panel.stack ? true : null; + + var xLabel = ""; + + + // Populate element + try { + var options = { + legend: { show: false }, + series: { + stackpercent: scope.panel.stack ? scope.panel.percentage : false, + stack: scope.panel.percentage ? null : stack, + lines: { + show: scope.panel.lines, + // Silly, but fixes bug in stacked percentages + fill: scope.panel.fill === 0 ? 0.001 : scope.panel.fill/10, + lineWidth: scope.panel.linewidth, + steps: false + }, + bars: { + show: scope.panel.bars, + fill: 1, + barWidth: barwidth/1.8, + zero: false, + lineWidth: 0 + }, + points: { + show: scope.panel.points, + fill: 1, + fillColor: false, + radius: 5 + }, + shadowSize: 1 + }, + axisLabels: { + show: true + }, + yaxis: { + show: scope.panel['y-axis'], + min:0, + + //min: null, // TODO - make this adjusted dynamicmally, and add it to configuration panel + //max: scope.panel.percentage && scope.panel.stack ? 100 : null, + axisLabel: scope.panel.mode, + }, + xaxis: { + timezone: scope.panel.timezone, + show: 1, + mode: "time", + + //min: _.isUndefined(scope.range.from) ? null : scope.range.from.getTime(), + //max: _.isUndefined(scope.range.to) ? null : scope.range.to.getTime(), + timeformat: time_format(scope.panel.interval), + label: "Datetime", + axisLabel: scope.panel['x-axis']?xLabel:'', + }, + grid: { + backgroundColor: null, + borderWidth: 0, + hoverable: true, + color: '#c8c8c8' + } + }; + + if(scope.panel.interactive) { + options.selection = { mode: "x", color: '#666' }; + } + + // when rendering stacked bars, we need to ensure each point that has data is zero-filled + // so that the stacking happens in the proper order + var required_times = []; + if (scope.data.length > 1) { + required_times = Array.prototype.concat.apply([], _.map(scope.data, function (query) { + return query.time_series.getOrderedTimes(); + })); + required_times = _.uniq(required_times.sort(function (a, b) { + // decending numeric sort + return a-b; + }), true); + } + + for (var i = 0; i < scope.data.length; i++) { + scope.data[i].data = scope.data[i].time_series.getFlotPairs(required_times); + } + + // ISSUE: SOL-76 + // If 'lines_smooth' is enabled, loop through $scope.data[] and remove zero filled entries. + // Without zero values, the line chart will appear smooth as SiLK ;-) + if (scope.panel.lines_smooth) { + for (var i=0; i < scope.data.length; i++) { // jshint ignore: line + var new_data = []; + for (var j=0; j < scope.data[i].data.length; j++) { + // if value of the timestamp !== 0, then add it to new_data + if (scope.data[i].data[j][1] !== 0) { + new_data.push(scope.data[i].data[j]); + } + } + scope.data[i].data = new_data; + } + } + + scope.plot = $.plot(elem, scope.data, options); + } catch(e) { + // TODO: Need to fix bug => "Invalid dimensions for plot, width = 0, height = 200" + // console.log(e); + } + } + + function time_format(interval) { + var _int = kbn.interval_to_seconds(interval); + if(_int >= 2628000) { + return "%m/%y"; + } + if(_int >= 86400) { + return "%m/%d/%y"; + } + if(_int >= 60) { + return "%H:%M
%m/%d"; + } + + return "%H:%M:%S"; + } + + var $tooltip = $('
'); + /* + elem.bind("plothover", function (event, pos, item) { + var group, value; + var allSeries = scope.plot.getData(); + if (item) { + + if (item.series.info.alias.substring(0,item.series.info.alias.length-2) || scope.panel.tooltip.query_as_alias) { + group = '' + + '' + ' ' + + (item.series.info.alias.substring(0,item.series.info.alias.length-2) || item.series.info.query)+ + '
'; + } else { + group = kbn.query_color_dot(item.series.color, 15) + ' '; + } + if (scope.panel.stack && scope.panel.tooltip.value_type === 'individual') { + value = item.datapoint[1] - item.datapoint[2]; + } else { + value = item.datapoint[1]; + } + $tooltip + .html( + group + dashboard.numberWithCommas(value) + " @ " + (scope.panel.timezone === 'utc'? moment.utc(item.datapoint[0]).format('MM/DD HH:mm:ss') : moment(item.datapoint[0]).format('MM/DD HH:mm:ss')) + // group + dashboard.numberWithCommas(value) + " @ " + moment(item.datapoint[0]).format('MM/DD HH:mm:ss') + // group + dashboard.numberWithCommas(value) + " @ " + moment(item.datapoint[0]) + ) + .place_tt(pos.pageX, pos.pageY); + } else { + $tooltip.detach(); + } + }); + */ + + elem.bind("plothover", function (event, pos, item) { + var group, value; + if (item) { + if (item.series.info.alias || scope.panel.tooltip.query_as_alias) { + group = '' + + '' + ' ' + + (item.series.info.alias || item.series.info.query)+ + '
'; + } else { + group = kbn.query_color_dot(item.series.color, 15) + ' '; + } + if (scope.panel.stack && scope.panel.tooltip.value_type === 'individual') { + value = item.datapoint[1] - item.datapoint[2]; + } else { + value = item.datapoint[1]; + } + + var lnLastValue = value; + var isr =0; + var isnormal = 3; + + var lbPositiveValue = (lnLastValue>0); + + var lsItemTT=""; + var lsTT=""; + var isgroup = group; + var isvalue = value; + if(scope.panel.mode !== 'value' || lnLastValue !== 0){ + lsItemTT = group + dashboard.numberWithCommas(value) + " @ " + (scope.panel.timezone === 'utc'? moment.utc(item.datapoint[0]).format('MM/DD HH:mm:ss') : moment(item.datapoint[0]).format('MM/DD HH:mm:ss')); + lsTT = lsItemTT; + isr =1; + }else{ + isnormal--; + } + + var hoverSeries = item.series; + var x = item.datapoint[0]; + // y = item.datapoint[1]; + + + var allSeries = scope.plot.getData(); + var posSerie = -1; + for (var i= allSeries.length - 1 ; i>=0; i--) { + + //if stack stop at the first positive value + if (scope.panel.stack && lbPositiveValue){ + break; + } + + var s = allSeries[i]; + i = parseInt(i); + + + if (s === hoverSeries ) { + posSerie = i; + } + + //not consider serie "upper" the hover serie + if ( i >= posSerie ){ + continue; + } + + //search in current serie a point with de same position. + for(var j= 0; j< s.data.length;j++){ + var p = s.data[j]; + if (p[0] === x ){ + + if (scope.panel.stack && scope.panel.tooltip.value_type === 'individual' && !isNaN(p[2])) { + value = p[1] - p[2]; + } else { + value = p[1]; + } + + lbPositiveValue = value > 0; + + if (! scope.panel.stack && value !== lnLastValue){ + break; + } + + posSerie = i; + lnLastValue = value; + + + if (s.info.alias || scope.panel.tooltip.query_as_alias) { + group = '' + + '' + ' ' + + (s.info.alias || s.info.query)+ + '
'; + } else { + group = kbn.query_color_dot(s.color, 15) + ' '; + } + + if(scope.panel.mode !== 'value' || lnLastValue !== 0){ + + lsItemTT = group + dashboard.numberWithCommas(value) + " @ " + (scope.panel.timezone === 'utc'? moment.utc(p[0]).format('MM/DD HH:mm:ss') : moment(p[0]).format('MM/DD HH:mm:ss')); + lsTT = lsTT +"
"+ lsItemTT; + isr=1; + }else{ + isnormal--; + } + break; + } + } + } + + + if(!isnormal){ + lsItemTT = isgroup + dashboard.numberWithCommas(isvalue) + " @ " + (scope.panel.timezone === 'utc'? moment.utc(item.datapoint[0]).format('MM/DD HH:mm:ss') : moment(item.datapoint[0]).format('MM/DD HH:mm:ss')); + lsTT = lsItemTT; + isr=1; + } + if(isr){ + $tooltip + .html( lsTT ) + .place_tt(pos.pageX, pos.pageY); + } + } else { + $tooltip.detach(); + } + }); + elem.bind("plotselected", function (event, ranges) { + + filterSrv.set({ + type: 'time', + // from : moment.utc(ranges.xaxis.from), + // to : moment.utc(ranges.xaxis.to), + from: moment.utc(ranges.xaxis.from).toDate(), + to: moment.utc(ranges.xaxis.to).toDate(), + field: filterSrv.getTimeField() + }); + dashboard.current.linkage_id = $scope.panel.linkage_id; + dashboard.current.enable_linkage =false; + dashboard.refresh(); + + }); + } + }; + }); + +}); diff --git a/src/app/panels/simplegram/timeSeries.js b/src/app/panels/simplegram/timeSeries.js new file mode 100644 index 000000000..96054fa7d --- /dev/null +++ b/src/app/panels/simplegram/timeSeries.js @@ -0,0 +1,179 @@ +define([ + 'underscore', + './interval' +], +function (_, Interval) { + 'use strict'; + + var ts = {}; + + // map compatable parseInt + function base10Int(val) { + return parseInt(val, 10); + } + + // trim the ms off of a time, but return it with empty ms. + function getDatesTime(date) { + return Math.floor(date.getTime() / 1000)*1000; + } + + /** + * Certain graphs require 0 entries to be specified for them to render + * properly (like the line graph). So with this we will caluclate all of + * the expected time measurements, and fill the missing ones in with 0 + * @param {object} opts An object specifying some/all of the options + * + * OPTIONS: + * @opt {string} interval The interval notion describing the expected spacing between + * each data point. + * @opt {date} start_date (optional) The start point for the time series, setting this and the + * end_date will ensure that the series streches to resemble the entire + * expected result + * @opt {date} end_date (optional) The end point for the time series, see start_date + * @opt {string} fill_style Either "minimal", or "all" describing the strategy used to zero-fill + * the series. + */ + ts.ZeroFilled = function (opts) { + opts = _.defaults(opts, { + interval: '10m', + start_date: null, + end_date: null, + fill_style: 'minimal' + }); + + // the expected differenece between readings. + this.interval = new Interval(opts.interval); + + // will keep all values here, keyed by their time + this._data = {}; + this.start_time = opts.start_date && getDatesTime(opts.start_date); + this.end_time = opts.end_date && getDatesTime(opts.end_date); + this.opts = opts; + }; + + /** + * Add a row + * @param {int} time The time for the value, in + * @param {any} value The value at this time + */ + ts.ZeroFilled.prototype.addValue = function (time, value) { + if (time instanceof Date) { + time = getDatesTime(time); + } else { + time = base10Int(time); + } + if (!isNaN(time)) { + this._data[time] = (_.isUndefined(value) ? 0 : value); + } + this._cached_times = null; + }; + + /** + * Get an array of the times that have been explicitly set in the series + * @param {array} include (optional) list of timestamps to include in the response + * @return {array} An array of integer times. + */ + ts.ZeroFilled.prototype.getOrderedTimes = function (include) { + var times = _.map(_.keys(this._data), base10Int); + if (_.isArray(include)) { + times = times.concat(include); + } + return _.uniq(times.sort(function (a, b) { + // decending numeric sort + return a - b; + }), true); + }; + + /** + * return the rows in the format: + * [ [time, value], [time, value], ... ] + * + * Heavy lifting is done by _get(Min|All)FlotPairs() + * @param {array} required_times An array of timestamps that must be in the resulting pairs + * @return {array} + */ + ts.ZeroFilled.prototype.getFlotPairs = function (required_times) { + var times = this.getOrderedTimes(required_times), + strategy, + pairs; + + if(this.opts.fill_style === 'all') { + strategy = this._getAllFlotPairs; + } else { + strategy = this._getMinFlotPairs; + } + + pairs = _.reduce( + times, // what + strategy, // how + [], // where + this // context + ); + + // if the first or last pair is inside either the start or end time, + // add those times to the series with null values so the graph will stretch to contain them. + if (this.start_time && (pairs.length === 0 || pairs[0][0] > this.start_time)) { + pairs.unshift([this.start_time, null]); + } + if (this.end_time && (pairs.length === 0 || pairs[pairs.length - 1][0] < this.end_time)) { + pairs.push([this.end_time, null]); + } + + return pairs; + }; + + /** + * ** called as a reduce stragegy in getFlotPairs() ** + * Fill zero's on either side of the current time, unless there is already a measurement there or + * we are looking at an edge. + * @return {array} An array of points to plot with flot + */ + ts.ZeroFilled.prototype._getMinFlotPairs = function (result, time, i, times) { + var next, expected_next, prev, expected_prev; + + // check for previous measurement + if (i > 0) { + prev = times[i - 1]; + expected_prev = this.interval.before(time); + if (prev < expected_prev) { + result.push([expected_prev, 0]); + } + } + + // add the current time + result.push([ time, this._data[time] || 0 ]); + + // check for next measurement + if (times.length > i) { + next = times[i + 1]; + expected_next = this.interval.after(time); + if (next > expected_next) { + result.push([expected_next, 0]); + } + } + + return result; + }; + + /** + * ** called as a reduce stragegy in getFlotPairs() ** + * Fill zero's to the right of each time, until the next measurement is reached or we are at the + * last measurement + * @return {array} An array of points to plot with flot + */ + ts.ZeroFilled.prototype._getAllFlotPairs = function (result, time, i, times) { + var next, expected_next; + + result.push([ times[i], this._data[times[i]] || 0 ]); + next = times[i + 1]; + expected_next = this.interval.after(time); + for(; times.length > i && next > expected_next; expected_next = this.interval.after(expected_next)) { + result.push([expected_next, 0]); + } + + return result; + }; + + + return ts; +}); \ No newline at end of file diff --git a/src/app/panels/sortbar/editor.html b/src/app/panels/sortbar/editor.html new file mode 100644 index 000000000..b63a1bb73 --- /dev/null +++ b/src/app/panels/sortbar/editor.html @@ -0,0 +1,54 @@ +
+
+ + + + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ In {{panel.mode}} mode the configured field must be a numeric type. +
+
+ + +
+
+ +
+ +
+
+
+ + +
+
+
+
Linkage Effective
+
+ +
+ +
+ + + + + + diff --git a/src/app/panels/sortbar/interval.js b/src/app/panels/sortbar/interval.js new file mode 100644 index 000000000..673371fcf --- /dev/null +++ b/src/app/panels/sortbar/interval.js @@ -0,0 +1,57 @@ +define([ + 'kbn' +], +function (kbn) { + 'use strict'; + + /** + * manages the interval logic + * @param {[type]} interval_string An interval string in the format '1m', '1y', etc + */ + function Interval(interval_string) { + this.string = interval_string; + + var info = kbn.describe_interval(interval_string); + this.type = info.type; + this.ms = info.sec * 1000 * info.count; + + // does the length of the interval change based on the current time? + if (this.type === 'y' || this.type === 'M') { + // we will just modify this time object rather that create a new one constantly + this.get = this.get_complex; + this.date = new Date(0); + } else { + this.get = this.get_simple; + } + } + + Interval.prototype = { + toString: function () { + return this.string; + }, + after: function(current_ms) { + return this.get(current_ms, 1); + }, + before: function (current_ms) { + return this.get(current_ms, -1); + }, + get_complex: function (current, delta) { + this.date.setTime(current); + switch(this.type) { + case 'M': + this.date.setUTCMonth(this.date.getUTCMonth() + delta); + break; + case 'y': + this.date.setUTCFullYear(this.date.getUTCFullYear() + delta); + break; + } + return this.date.getTime(); + }, + get_simple: function (current, delta) { + return current + (delta * this.ms); + } + }; + + return Interval; + +}); \ No newline at end of file diff --git a/src/app/panels/sortbar/module.html b/src/app/panels/sortbar/module.html new file mode 100644 index 000000000..ed453c8e9 --- /dev/null +++ b/src/app/panels/sortbar/module.html @@ -0,0 +1,117 @@ +
+ + + +
+ +
+ + + + + + +
{{term.label}}{{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}
+ + +
+ {{term.label}} ({{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}) +

+ +
+
{{data.length - 2}}
+ +
+ +
+ + + + + + +
{{term.label}}{{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}
+
+ +
+ +
+ + + + + + +
{{term.label}}{{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}
+ + +
+ {{term.label}} ({{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}) +

+ +
+ + + + + + + + + + + + + + + + +
Term{{panel.mode | capitalize}}Action
{{term.label}}{{term.data[0][1].toFixed(panel.decimal_points)}} + + + + +
+ + +
+
+
diff --git a/src/app/panels/sortbar/module.js b/src/app/panels/sortbar/module.js new file mode 100644 index 000000000..4d255e8cb --- /dev/null +++ b/src/app/panels/sortbar/module.js @@ -0,0 +1,654 @@ +/* + + ## Histogram + + ### Parameters + * auto_int :: Auto calculate data point interval? + * resolution :: If auto_int is enables, shoot for this many data points, rounding to + sane intervals + * interval :: Datapoint interval in elasticsearch date math format (eg 1d, 1w, 1y, 5y) + * fill :: Only applies to line charts. Level of area shading from 0-10 + * linewidth :: Only applies to line charts. How thick the line should be in pixels + While the editor only exposes 0-10, this can be any numeric value. + Set to 0 and you'll get something like a scatter plot + * timezone :: This isn't totally functional yet. Currently only supports browser and utc. + browser will adjust the x-axis labels to match the timezone of the user's + browser + * spyable :: Dislay the 'eye' icon that show the last elasticsearch query + * zoomlinks :: Show the zoom links? + * bars :: Show bars in the chart + * stack :: Stack multiple queries. This generally a crappy way to represent things. + You probably should just use a line chart without stacking + * points :: Should circles at the data points on the chart + * lines :: Line chart? Sweet. + * legend :: Show the legend? + * x-axis :: Show x-axis labels and grid lines + * y-axis :: Show y-axis labels and grid lines + * interactive :: Allow drag to select time range + +*/ +define([ + 'angular', + 'app', + 'jquery', + 'underscore', + 'kbn', + 'moment', + './timeSeries' + + +], +function (angular, app, $, _, kbn, moment, timeSeries) { + 'use strict'; + + var module = angular.module('kibana.panels.sortbar', []); + app.useModule(module); + + module.controller('sortbar', function($scope, $q, querySrv, dashboard, filterSrv) { + $scope.panelMeta = { + + editorTabs : [ + { + title:'Queries', + src:'app/partials/querySelect.html' + } + ], + status : "Stable", + description : "A bucketed time series chart of the current query, including all applied time and non-time filters, when used in count mode. Uses Solr’s facet.range query parameters. In values mode, it plots the value of a specific field over time, and allows the user to group field values by a second field." + }; + + // Set and populate defaults + var _d = { + mode : 'value', + queries : { + mode : 'all', + ids : [], + query : '*:*', + custom : '' + }, + max_rows : 10, // maximum number of rows returned from Solr (also use this for group.limit to simplify UI setting) + reverse :0, + segment :4, + threshold_first:1000, + threshold_second:2000, + threshold_third:3000, + value_field : '', + linkage_id:'a', + group_field : null, + auto_int : true, + total_first :'%', + fontsize:12, + ylabels:false, + field_color:'#209bf8', + resolution : 100, + value_sort :'rs_timestamp', + interval : '5m', + intervals : ['auto','1s','1m','5m','10m','30m','1h','3h','12h','1d','1w','1M','1y'], + fill : 0, + linewidth : 3, + chart :'sortbar', + chartColors :querySrv.colors, + timezone : 'browser', // browser, utc or a standard timezone + spyable : true, + linkage :false, + zoomlinks : true, + bars : true, + stack : true, + label : true, + points : false, + display:'block', + icon:"icon-caret-down", + lines : false, + lines_smooth: false, // Enable 'smooth line' mode by removing zero values from the plot. + legend : true, + 'x-axis' : true, + 'y-axis' : true, + percentage : false, + interactive : true, + options : true, + show_queries:true, + tooltip : { + value_type: 'cumulative', + query_as_alias: false + } + }; + + _.defaults($scope.panel,_d); + + $scope.init = function() { + // Hide view options by default + $scope.options = false; + $scope.$on('refresh',function(){ + $scope.get_data(); + }); + + $scope.get_data(); + + }; + + $scope.set_interval = function(interval) { + if(interval !== 'auto') { + $scope.panel.auto_int = false; + $scope.panel.interval = interval; + } else { + $scope.panel.auto_int = true; + } + }; + + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; + + $scope.interval_label = function(interval) { + return $scope.panel.auto_int && interval === $scope.panel.interval ? interval+" (auto)" : interval; + }; + + /** + * The time range effecting the panel + * @return {[type]} [description] + */ + $scope.get_time_range = function () { + var range = $scope.range = filterSrv.timeRange('min'); + return range; + }; + + $scope.get_interval = function () { + var interval = $scope.panel.interval, + range; + if ($scope.panel.auto_int) { + range = $scope.get_time_range(); + if (range) { + interval = kbn.secondsToHms( + kbn.calculate_interval(range.from, range.to, $scope.panel.resolution, 0) / 1000 + ); + } + } + $scope.panel.interval = interval || '10m'; + return $scope.panel.interval; + }; + + /** + * Fetch the data for a chunk of a queries results. Multiple segments occur when several indicies + * need to be consulted (like timestamped logstash indicies) + * + * The results of this function are stored on the scope's data property. This property will be an + * array of objects with the properties info, time_series, and hits. These objects are used in the + * render_panel function to create the historgram. + * + * !!! Solr does not need to fetch the data in chunk because it uses a facet search and retrieve + * !!! all events from a single query. + * + * @param {number} segment The segment count, (0 based) + * @param {number} query_id The id of the query, generated on the first run and passed back when + * this call is made recursively for more segments + */ + $scope.get_data = function(segment, query_id) { + if(($scope.panel.linkage_id === dashboard.current.linkage_id)||dashboard.current.enable_linkage){ + if (_.isUndefined(segment)) { + segment = 0; + } + delete $scope.panel.error; + + // Make sure we have everything for the request to complete + if (dashboard.indices.length === 0) { + return; + } + var _range = $scope.get_time_range(); + var _interval = $scope.get_interval(_range); + + if ($scope.panel.auto_int) { + $scope.panel.interval = kbn.secondsToHms( + kbn.calculate_interval(_range.from, _range.to, $scope.panel.resolution, 0) / 1000); + } + + $scope.panelMeta.loading = true; + + // Solr + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + var request = $scope.sjs.Request().indices(dashboard.indices[segment]); + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + + + $scope.panel.queries.query = ""; + // Build the query + _.each($scope.panel.queries.ids, function (id) { + var query = $scope.sjs.FilteredQuery( + querySrv.getEjsObj(id), + filterSrv.getBoolFilter(filterSrv.ids) + ); + + var facet = $scope.sjs.DateHistogramFacet(id); + if ($scope.panel.mode === 'count' || $scope.panel.mode === 'counts') { + facet = facet.field(filterSrv.getTimeField()); + } else { + if (_.isNull($scope.panel.value_field)) { + $scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified"; + return; + } + facet = facet.keyField(filterSrv.getTimeField()).valueField($scope.panel.value_field); + } + facet = facet.interval(_interval).facetFilter($scope.sjs.QueryFilter(query)); + request = request.facet(facet).size(0); + + }); + + // Populate the inspector panel + $scope.populate_modal(request); + + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + } + var time_field = filterSrv.getTimeField(); + var start_time = filterSrv.getStartTime(); + var end_time = filterSrv.getEndTime(); + + // facet.range.end does NOT accept * as a value, need to convert it to NOW + if (end_time === '*') { + end_time = 'NOW'; + } + + var wt_json = '&wt=json'; + var sort_s = '&sort=' + $scope.panel.value_sort + '%20desc'; + var rows_limit = '&rows=0'; // for histogram, we do not need the actual response doc, so set rows=0 + var facet_gap = $scope.sjs.convertFacetGap($scope.panel.interval); + var facet = '&facet=true' + + '&facet.range=' + time_field + + '&facet.range.start=' + start_time + + '&facet.range.end=' + end_time + + '&facet.range.gap=' + facet_gap; + var values_mode_query = ''; + + // For mode = value + if ($scope.panel.mode === 'values' || $scope.panel.mode === 'value') { + if (!$scope.panel.value_field) { + $scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified"; + return; + } + values_mode_query = '&fl=' + time_field + ' ' + $scope.panel.value_field; + + rows_limit = '&rows=' + $scope.panel.max_rows; + facet = ''; + + // if Group By Field is specified + if ($scope.panel.group_field) { + values_mode_query += '&group=true&group.field=' + $scope.panel.group_field + '&group.limit=' + $scope.panel.max_rows; + } + } + + var mypromises = []; + if ($scope.panel.mode === 'value' || $scope.panel.mode === 'counts') { + var arr_id = [0]; + _.each(arr_id, function () { + var temp_q = 'q=' + $scope.panel.value_field + '%3A%5B' + '*' + '%20TO%20' + '*' + '%5D' + wt_json + sort_s + rows_limit + fq + facet + values_mode_query; + + $scope.panel.queries.query += temp_q + "\n"; + if ($scope.panel.queries.custom !== null) { + request = request.setQuery(temp_q + $scope.panel.queries.custom); + } else { + request = request.setQuery(temp_q); + } + mypromises.push(request.doSearch()); + }); + } + $scope.data = []; + + if (dashboard.current.services.query.ids.length >= 1) { + $q.all(mypromises).then(function (results) { + $scope.panelMeta.loading = false; + if (segment === 0) { + $scope.hits = 0; + $scope.data = []; + query_id = $scope.query_id = new Date().getTime(); + } + // Convert facet ids to numbers + // var facetIds = _.map(_.keys(results.facets),function(k){return parseInt(k, 10);}); + //var facetIds = [0]; // Need to fix this + + // Make sure we're still on the same query/queries + // TODO: We probably DON'T NEED THIS unless we have to support multiple queries in query module. + // if ($scope.query_id === query_id && _.difference(facetIds, $scope.panel.queries.ids).length === 0) { + var i = 0, + time_series, + hits; + + _.each(arr_id, function (id, index) { + // Check for error and abort if found + if (!(_.isUndefined(results[index].error))) { + $scope.panel.error = $scope.parse_error(results[index].error.msg); + return; + } + // we need to initialize the data variable on the first run, + // and when we are working on the first segment of the data. + if (_.isUndefined($scope.data[i]) || segment === 0) { + time_series = new timeSeries.ZeroFilled({ + interval: _interval, + start_date: _range && _range.from, + end_date: _range && _range.to, + fill_style: 'minimal' + }); + hits = 0; + } else { + time_series = $scope.data[i].time_series; + // Bug fix for wrong event count: + // Solr don't need to accumulate hits count since it can get total count from facet query. + // Therefore, I need to set hits and $scope.hits to zero. + // hits = $scope.data[i].hits; + hits = 0; + $scope.hits = 0; + } + + + $scope.data[i] = results[index].response.docs; + + + i++; + }); + + // Tell the histogram directive to render. + $scope.$emit('render'); + // } + }); + } + + } + }; + + // function $scope.zoom + // factor :: Zoom factor, so 0.5 = cuts timespan in half, 2 doubles timespan + $scope.zoom = function(factor) { + var _range = filterSrv.timeRange('min'); + var _timespan = (_range.to.valueOf() - _range.from.valueOf()); + var _center = _range.to.valueOf() - _timespan/2; + + var _to = (_center + (_timespan*factor)/2); + var _from = (_center - (_timespan*factor)/2); + + // If we're not already looking into the future, don't. + if(_to > Date.now() && _range.to < Date.now()) { + var _offset = _to - Date.now(); + _from = _from - _offset; + _to = Date.now(); + } + + var time_field = filterSrv.getTimeField(); + if(factor > 1) { + filterSrv.removeByType('time'); + } + + filterSrv.set({ + type:'time', + from:moment.utc(_from).toDate(), + to:moment.utc(_to).toDate(), + field:time_field + }); + + dashboard.refresh(); + }; + + // I really don't like this function, too much dom manip. Break out into directive? + $scope.populate_modal = function(request) { + $scope.inspector = angular.toJson(JSON.parse(request.toString()),true); + }; + + $scope.set_refresh = function (state) { + $scope.refresh = state; + }; + + $scope.close_edit = function() { + if($scope.refresh) { + $scope.get_data(); + } + $scope.refresh = false; + $scope.$emit('render'); + }; + + $scope.render = function() { + $scope.$emit('render'); + }; + + }); + + module.directive('sortbarChart', function(querySrv,dashboard,filterSrv) { + return { + restrict: 'A', + link: function(scope, elem) { + var myChart; + // Receive render events + scope.$on('render',function(){ + render_panel(); + }); + + // Re-render if the window is resized + angular.element(window).bind('resize', function(){ + render_panel(); + }); + + // Function for rendering panel + function render_panel() { + var chartData; + var colors = []; + + // IE doesn't work without this + elem.css({height:scope.panel.height||scope.row.height}); + + // Make a clone we can operate on. + + chartData = _.clone(scope.data); + chartData = scope.panel.missing ? chartData : + _.without(chartData,_.findWhere(chartData,{meta:'missing'})); + chartData = scope.panel.other ? chartData : + _.without(chartData,_.findWhere(chartData,{meta:'other'})); + + if (filterSrv.idsByTypeAndField('terms',scope.panel.field).length > 0) { + colors.push(scope.panel.lastColor); + } else { + colors = scope.panel.chartColors; + } + + var barData = []; + var barDataLabel=[]; + var barLabel = scope.panel.value_field.split(" "); + + + + + for (var i =0;i this.start_time)) { + pairs.unshift([this.start_time, null]); + } + if (this.end_time && (pairs.length === 0 || pairs[pairs.length - 1][0] < this.end_time)) { + pairs.push([this.end_time, null]); + } + + return pairs; + }; + + /** + * ** called as a reduce stragegy in getFlotPairs() ** + * Fill zero's on either side of the current time, unless there is already a measurement there or + * we are looking at an edge. + * @return {array} An array of points to plot with flot + */ + ts.ZeroFilled.prototype._getMinFlotPairs = function (result, time, i, times) { + var next, expected_next, prev, expected_prev; + + // check for previous measurement + if (i > 0) { + prev = times[i - 1]; + expected_prev = this.interval.before(time); + if (prev < expected_prev) { + result.push([expected_prev, 0]); + } + } + + // add the current time + result.push([ time, this._data[time] || 0 ]); + + // check for next measurement + if (times.length > i) { + next = times[i + 1]; + expected_next = this.interval.after(time); + if (next > expected_next) { + result.push([expected_next, 0]); + } + } + + return result; + }; + + /** + * ** called as a reduce stragegy in getFlotPairs() ** + * Fill zero's to the right of each time, until the next measurement is reached or we are at the + * last measurement + * @return {array} An array of points to plot with flot + */ + ts.ZeroFilled.prototype._getAllFlotPairs = function (result, time, i, times) { + var next, expected_next; + + result.push([ times[i], this._data[times[i]] || 0 ]); + next = times[i + 1]; + expected_next = this.interval.after(time); + for(; times.length > i && next > expected_next; expected_next = this.interval.after(expected_next)) { + result.push([expected_next, 0]); + } + + return result; + }; + + + return ts; +}); \ No newline at end of file diff --git a/src/app/panels/stacking/editor.html b/src/app/panels/stacking/editor.html new file mode 100644 index 000000000..afac5f358 --- /dev/null +++ b/src/app/panels/stacking/editor.html @@ -0,0 +1,171 @@ +
+
+ + + + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ In {{panel.mode}} mode the configured field must be a numeric type. +
+
+ + +
+
+ +
+
+ +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+ +
+
+ + +
+
+ +
+
+ + +
+ +
+ +
Chart Settings
+
+
+
+
+
+
+ + +
+
+
+
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ +
Tooltip Settings
+
+
+ + +
+
+ + +
+
+
+
Linkage Effective
+
+ +
+ +
diff --git a/src/app/panels/stacking/interval.js b/src/app/panels/stacking/interval.js new file mode 100644 index 000000000..673371fcf --- /dev/null +++ b/src/app/panels/stacking/interval.js @@ -0,0 +1,57 @@ +define([ + 'kbn' +], +function (kbn) { + 'use strict'; + + /** + * manages the interval logic + * @param {[type]} interval_string An interval string in the format '1m', '1y', etc + */ + function Interval(interval_string) { + this.string = interval_string; + + var info = kbn.describe_interval(interval_string); + this.type = info.type; + this.ms = info.sec * 1000 * info.count; + + // does the length of the interval change based on the current time? + if (this.type === 'y' || this.type === 'M') { + // we will just modify this time object rather that create a new one constantly + this.get = this.get_complex; + this.date = new Date(0); + } else { + this.get = this.get_simple; + } + } + + Interval.prototype = { + toString: function () { + return this.string; + }, + after: function(current_ms) { + return this.get(current_ms, 1); + }, + before: function (current_ms) { + return this.get(current_ms, -1); + }, + get_complex: function (current, delta) { + this.date.setTime(current); + switch(this.type) { + case 'M': + this.date.setUTCMonth(this.date.getUTCMonth() + delta); + break; + case 'y': + this.date.setUTCFullYear(this.date.getUTCFullYear() + delta); + break; + } + return this.date.getTime(); + }, + get_simple: function (current, delta) { + return current + (delta * this.ms); + } + }; + + return Interval; + +}); \ No newline at end of file diff --git a/src/app/panels/stacking/module.html b/src/app/panels/stacking/module.html new file mode 100644 index 000000000..6b5ddd63f --- /dev/null +++ b/src/app/panels/stacking/module.html @@ -0,0 +1,116 @@ +
+ + +
+ +
+ + + + + + +
{{term.label}}{{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}
+ + +
+ {{term.label}} ({{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}) +

+ +
+
{{data.length - 2}}
+ +
+ +
+ + + + + + +
{{term.label}}{{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}
+
+ +
+ +
+ + + + + + +
{{term.label}}{{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}
+ + +
+ {{term.label}} ({{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}) +

+ +
+ + + + + + + + + + + + + + + + +
Term{{panel.mode | capitalize}}Action
{{term.label}}{{term.data[0][1].toFixed(panel.decimal_points)}} + + + + +
+ + +
+
+
diff --git a/src/app/panels/stacking/module.js b/src/app/panels/stacking/module.js new file mode 100644 index 000000000..c6c57faae --- /dev/null +++ b/src/app/panels/stacking/module.js @@ -0,0 +1,930 @@ +/* + + ## Histogram + + ### Parameters + * auto_int :: Auto calculate data point interval? + * resolution :: If auto_int is enables, shoot for this many data points, rounding to + sane intervals + * interval :: Datapoint interval in elasticsearch date math format (eg 1d, 1w, 1y, 5y) + * fill :: Only applies to line charts. Level of area shading from 0-10 + * linewidth :: Only applies to line charts. How thick the line should be in pixels + While the editor only exposes 0-10, this can be any numeric value. + Set to 0 and you'll get something like a scatter plot + * timezone :: This isn't totally functional yet. Currently only supports browser and utc. + browser will adjust the x-axis labels to match the timezone of the user's + browser + * spyable :: Dislay the 'eye' icon that show the last elasticsearch query + * zoomlinks :: Show the zoom links? + * bars :: Show bars in the chart + * stack :: Stack multiple queries. This generally a crappy way to represent things. + You probably should just use a line chart without stacking + * points :: Should circles at the data points on the chart + * lines :: Line chart? Sweet. + * legend :: Show the legend? + * x-axis :: Show x-axis labels and grid lines + * y-axis :: Show y-axis labels and grid lines + * interactive :: Allow drag to select time range + +*/ +define([ + 'angular', + 'app', + 'jquery', + 'underscore', + 'kbn', + 'moment', + './timeSeries' + + +], +function (angular, app, $, _, kbn, moment, timeSeries) { + 'use strict'; + var module = angular.module('kibana.panels.stacking', []); + app.useModule(module); + + module.controller('stacking', function($scope, $q, querySrv, dashboard, filterSrv) { + $scope.panelMeta = { + + editorTabs : [ + { + title:'Queries', + src:'app/partials/querySelect.html' + } + ], + status : "Stable", + description : "A bucketed time series chart of the current query, including all applied time and non-time filters, when used in count mode. Uses Solr’s facet.range query parameters. In values mode, it plots the value of a specific field over time, and allows the user to group field values by a second field." + }; + + // Set and populate defaults + var _d = { + mode : 'value', + queries : { + mode : 'all', + ids : [], + query : '*:*', + custom : '' + }, + max_rows : 100000, // maximum number of rows returned from Solr (also use this for group.limit to simplify UI setting) + reverse :0, + segment :4, + threshold_first:1000, + threshold_second:2000, + threshold_third:3000, + value_field : 'redirectElapsed cacheElapsed dnsElapsed tcpElapsed requestElapsed responseElapsed domElapsed loadEventElapsed', + group_field : null, + auto_int : true, + total_first :'%', + fontsize:20, + isEN:false, + field_color:'#209bf8', + resolution : 100, + value_sort :'rs_timestamp', + interval : '5m', + intervals : ['auto','1s','1m','5m','10m','30m','1h','3h','12h','1d','1w','1M','1y'], + fill : 0, + linewidth : 3, + chart :'stacking', + chartColors :['#f48a52','#f4d352','#ccf452','#8cf452','#3cee2b','#f467d8','#1a93f9','#2fd7ee'], + timezone : 'browser', // browser, utc or a standard timezone + spyable : true, + linkage :false, + zoomlinks : true, + bars : true, + display:'block', + icon:"icon-caret-down", + stack : true, + linkage_id:'a', + label : true, + points : false, + lines : false, + lines_smooth: false, // Enable 'smooth line' mode by removing zero values from the plot. + legend : true, + 'x-axis' : true, + 'y-axis' : true, + percentage : false, + interactive : true, + options : true, + show_queries:true, + tooltip : { + value_type: 'cumulative', + query_as_alias: false + } + }; + + _.defaults($scope.panel,_d); + + $scope.init = function() { + // Hide view options by default + $scope.options = false; + $scope.$on('refresh',function(){ + $scope.get_data(); + }); + + $scope.get_data(); + + }; + + $scope.set_interval = function(interval) { + if(interval !== 'auto') { + $scope.panel.auto_int = false; + $scope.panel.interval = interval; + } else { + $scope.panel.auto_int = true; + } + }; + + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; + + $scope.interval_label = function(interval) { + return $scope.panel.auto_int && interval === $scope.panel.interval ? interval+" (auto)" : interval; + }; + + /** + * The time range effecting the panel + * @return {[type]} [description] + */ + $scope.get_time_range = function () { + var range = $scope.range = filterSrv.timeRange('min'); + return range; + }; + + $scope.get_interval = function () { + var interval = $scope.panel.interval, + range; + if ($scope.panel.auto_int) { + range = $scope.get_time_range(); + if (range) { + interval = kbn.secondsToHms( + kbn.calculate_interval(range.from, range.to, $scope.panel.resolution, 0) / 1000 + ); + } + } + $scope.panel.interval = interval || '10m'; + return $scope.panel.interval; + }; + + /** + * Fetch the data for a chunk of a queries results. Multiple segments occur when several indicies + * need to be consulted (like timestamped logstash indicies) + * + * The results of this function are stored on the scope's data property. This property will be an + * array of objects with the properties info, time_series, and hits. These objects are used in the + * render_panel function to create the historgram. + * + * !!! Solr does not need to fetch the data in chunk because it uses a facet search and retrieve + * !!! all events from a single query. + * + * @param {number} segment The segment count, (0 based) + * @param {number} query_id The id of the query, generated on the first run and passed back when + * this call is made recursively for more segments + */ + $scope.get_data = function(segment, query_id) { + if(($scope.panel.linkage_id === dashboard.current.linkage_id)||dashboard.current.enable_linkage){ + if (_.isUndefined(segment)) { + segment = 0; + } + delete $scope.panel.error; + + // Make sure we have everything for the request to complete + if (dashboard.indices.length === 0) { + return; + } + var _range = $scope.get_time_range(); + var _interval = $scope.get_interval(_range); + + if ($scope.panel.auto_int) { + $scope.panel.interval = kbn.secondsToHms( + kbn.calculate_interval(_range.from, _range.to, $scope.panel.resolution, 0) / 1000); + } + + $scope.panelMeta.loading = true; + + // Solr + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + var request = $scope.sjs.Request().indices(dashboard.indices[segment]); + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + + + $scope.panel.queries.query = ""; + // Build the query + _.each($scope.panel.queries.ids, function (id) { + var query = $scope.sjs.FilteredQuery( + querySrv.getEjsObj(id), + filterSrv.getBoolFilter(filterSrv.ids) + ); + + var facet = $scope.sjs.DateHistogramFacet(id); + if ($scope.panel.mode === 'count' || $scope.panel.mode === 'counts') { + facet = facet.field(filterSrv.getTimeField()); + } else { + if (_.isNull($scope.panel.value_field)) { + $scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified"; + return; + } + facet = facet.keyField(filterSrv.getTimeField()).valueField($scope.panel.value_field); + } + facet = facet.interval(_interval).facetFilter($scope.sjs.QueryFilter(query)); + request = request.facet(facet).size(0); + + }); + + // Populate the inspector panel + $scope.populate_modal(request); + + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + } + var time_field = filterSrv.getTimeField(); + var start_time = filterSrv.getStartTime(); + var end_time = filterSrv.getEndTime(); + + // facet.range.end does NOT accept * as a value, need to convert it to NOW + if (end_time === '*') { + end_time = 'NOW'; + } + + var wt_json = '&wt=json'; + var sort_s = '&sort=' + $scope.panel.value_sort + '%20asc'; + var rows_limit = '&rows=0'; // for histogram, we do not need the actual response doc, so set rows=0 + var facet_gap = $scope.sjs.convertFacetGap($scope.panel.interval); + var facet = '&facet=true' + + '&facet.range=' + time_field + + '&facet.range.start=' + start_time + + '&facet.range.end=' + end_time + + '&facet.range.gap=' + facet_gap; + var values_mode_query = ''; + + // For mode = value + if ($scope.panel.mode === 'values' || $scope.panel.mode === 'value') { + if (!$scope.panel.value_field) { + $scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified"; + return; + } + values_mode_query = '&fl=' + time_field + ' ' + $scope.panel.value_field; + + rows_limit = '&rows=' + $scope.panel.max_rows; + facet = ''; + + // if Group By Field is specified + if ($scope.panel.group_field) { + values_mode_query += '&group=true&group.field=' + $scope.panel.group_field + '&group.limit=' + $scope.panel.max_rows; + } + } + + var mypromises = []; + if ($scope.panel.mode === 'value' || $scope.panel.mode === 'counts') { + var arr_id = [0]; + _.each(arr_id, function () { + var temp_q = 'q=' + $scope.panel.value_field + '%3A%5B' + '*' + '%20TO%20' + '*' + '%5D' + wt_json + sort_s + rows_limit + fq + facet + values_mode_query; + + $scope.panel.queries.query += temp_q + "\n"; + if ($scope.panel.queries.custom !== null) { + request = request.setQuery(temp_q + $scope.panel.queries.custom); + } else { + request = request.setQuery(temp_q); + } + mypromises.push(request.doSearch()); + }); + } + $scope.data = []; + + if (dashboard.current.services.query.ids.length >= 1) { + $q.all(mypromises).then(function (results) { + $scope.panelMeta.loading = false; + if (segment === 0) { + $scope.hits = 0; + $scope.data = []; + query_id = $scope.query_id = new Date().getTime(); + } + // Convert facet ids to numbers + // var facetIds = _.map(_.keys(results.facets),function(k){return parseInt(k, 10);}); + //var facetIds = [0]; // Need to fix this + + // Make sure we're still on the same query/queries + // TODO: We probably DON'T NEED THIS unless we have to support multiple queries in query module. + // if ($scope.query_id === query_id && _.difference(facetIds, $scope.panel.queries.ids).length === 0) { + var i = 0, + time_series, + hits; + + _.each(arr_id, function (id, index) { + // Check for error and abort if found + if (!(_.isUndefined(results[index].error))) { + $scope.panel.error = $scope.parse_error(results[index].error.msg); + return; + } + // we need to initialize the data variable on the first run, + // and when we are working on the first segment of the data. + if (_.isUndefined($scope.data[i]) || segment === 0) { + time_series = new timeSeries.ZeroFilled({ + interval: _interval, + start_date: _range && _range.from, + end_date: _range && _range.to, + fill_style: 'minimal' + }); + hits = 0; + } else { + time_series = $scope.data[i].time_series; + // Bug fix for wrong event count: + // Solr don't need to accumulate hits count since it can get total count from facet query. + // Therefore, I need to set hits and $scope.hits to zero. + // hits = $scope.data[i].hits; + hits = 0; + $scope.hits = 0; + } + + $scope.data[i] = results[index].response.docs; + i++; + }); + + // Tell the histogram directive to render. + $scope.$emit('render'); + // } + }); + } + + } + }; + + // function $scope.zoom + // factor :: Zoom factor, so 0.5 = cuts timespan in half, 2 doubles timespan + $scope.zoom = function(factor) { + var _range = filterSrv.timeRange('min'); + var _timespan = (_range.to.valueOf() - _range.from.valueOf()); + var _center = _range.to.valueOf() - _timespan/2; + + var _to = (_center + (_timespan*factor)/2); + var _from = (_center - (_timespan*factor)/2); + + // If we're not already looking into the future, don't. + if(_to > Date.now() && _range.to < Date.now()) { + var _offset = _to - Date.now(); + _from = _from - _offset; + _to = Date.now(); + } + + var time_field = filterSrv.getTimeField(); + if(factor > 1) { + filterSrv.removeByType('time'); + } + + filterSrv.set({ + type:'time', + from:moment.utc(_from).toDate(), + to:moment.utc(_to).toDate(), + field:time_field + }); + + dashboard.refresh(); + }; + + // I really don't like this function, too much dom manip. Break out into directive? + $scope.populate_modal = function(request) { + $scope.inspector = angular.toJson(JSON.parse(request.toString()),true); + }; + + $scope.set_refresh = function (state) { + $scope.refresh = state; + }; + + $scope.close_edit = function() { + if($scope.refresh) { + $scope.get_data(); + } + $scope.refresh = false; + $scope.$emit('render'); + }; + + $scope.render = function() { + $scope.$emit('render'); + }; + + }); + + module.directive('stackingChart', function(querySrv,dashboard,filterSrv) { + return { + restrict: 'A', + link: function(scope, elem) { + var myChart; + // Receive render events + scope.$on('render',function(){ + render_panel(); + }); + + // Re-render if the window is resized + angular.element(window).bind('resize', function(){ + render_panel(); + }); + + // Function for rendering panel + function render_panel() { + var chartData; + var colors = []; + + // IE doesn't work without this + elem.css({height:scope.panel.height||scope.row.height}); + + // Make a clone we can operate on. + + chartData = _.clone(scope.data); + chartData = scope.panel.missing ? chartData : + _.without(chartData,_.findWhere(chartData,{meta:'missing'})); + chartData = scope.panel.other ? chartData : + _.without(chartData,_.findWhere(chartData,{meta:'other'})); + + if (filterSrv.idsByTypeAndField('terms',scope.panel.field).length > 0) { + colors.push(scope.panel.lastColor); + } else { + colors = scope.panel.chartColors; + } + + + + var domElapsed = []; + var rs_timestamp = []; + var redirectElapsed = []; + var cacheElapsed = []; + var loadEventElapsed = []; + + var dnsElapsed = []; + var tcpElapsed = []; + var requestElapsed = []; + var responseElapsed = []; + var secondtime ; + var selecttime = []; + + var sum_domElapsed = 0; + var sum_redirectElapsed = 0; + var sum_cacheElapsed = 0; + var sum_loadEventElapsed = 0; + var sum_dnsElapsed = 0; + var sum_tcpElapsed = 0; + var sum_requestElapsed = 0; + var sum_responseElapsed = 0; + Date.prototype.pattern = function (fmt) { + var o = { + "M+" : this.getMonth() + 1, //月份 + "d+" : this.getDate(), //æ—¥ + "h+" : this.getHours() % 12 === 0 ? 12 : this.getHours() % 12, //å°æ—¶ + "H+" : this.getHours(), //å°æ—¶ + "m+" : this.getMinutes(), //分 + "s+" : this.getSeconds(), //ç§’ + "q+" : Math.floor((this.getMonth() + 3) / 3), //季度 + "S" : this.getMilliseconds() //毫秒 + }; + var week = { + "0" : "/u65e5", + "1" : "/u4e00", + "2" : "/u4e8c", + "3" : "/u4e09", + "4" : "/u56db", + "5" : "/u4e94", + "6" : "/u516d" + }; + if (/(y+)/.test(fmt)) { + fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length)); + } + if (/(E+)/.test(fmt)) { + fmt = fmt.replace(RegExp.$1, ((RegExp.$1.length > 1) ? (RegExp.$1.length > 2 ? "/u661f/u671f" : "/u5468") : "") + week[this.getDay() + ""]); + } + for (var k in o) { + if (new RegExp("(" + k + ")").test(fmt)) { + fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); + } + } + return fmt; + }; + + + for (var i =0;i this.start_time)) { + pairs.unshift([this.start_time, null]); + } + if (this.end_time && (pairs.length === 0 || pairs[pairs.length - 1][0] < this.end_time)) { + pairs.push([this.end_time, null]); + } + + return pairs; + }; + + /** + * ** called as a reduce stragegy in getFlotPairs() ** + * Fill zero's on either side of the current time, unless there is already a measurement there or + * we are looking at an edge. + * @return {array} An array of points to plot with flot + */ + ts.ZeroFilled.prototype._getMinFlotPairs = function (result, time, i, times) { + var next, expected_next, prev, expected_prev; + + // check for previous measurement + if (i > 0) { + prev = times[i - 1]; + expected_prev = this.interval.before(time); + if (prev < expected_prev) { + result.push([expected_prev, 0]); + } + } + + // add the current time + result.push([ time, this._data[time] || 0 ]); + + // check for next measurement + if (times.length > i) { + next = times[i + 1]; + expected_next = this.interval.after(time); + if (next > expected_next) { + result.push([expected_next, 0]); + } + } + + return result; + }; + + /** + * ** called as a reduce stragegy in getFlotPairs() ** + * Fill zero's to the right of each time, until the next measurement is reached or we are at the + * last measurement + * @return {array} An array of points to plot with flot + */ + ts.ZeroFilled.prototype._getAllFlotPairs = function (result, time, i, times) { + var next, expected_next; + + result.push([ times[i], this._data[times[i]] || 0 ]); + next = times[i + 1]; + expected_next = this.interval.after(time); + for(; times.length > i && next > expected_next; expected_next = this.interval.after(expected_next)) { + result.push([expected_next, 0]); + } + + return result; + }; + + + return ts; +}); \ No newline at end of file diff --git a/src/app/panels/statistics/editor.html b/src/app/panels/statistics/editor.html new file mode 100755 index 000000000..949b18489 --- /dev/null +++ b/src/app/panels/statistics/editor.html @@ -0,0 +1,93 @@ +
+
+ + +
+
+ + +
+
+ + +
+
+ + + +
+
+ + +
+
+ + +
+
+ + + +
+ +
+ + +
+
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
+
+
Real-time (Auto-refresh)
+
+ +
+
+ + +
+
+
+
Linkage Effective
+
+ +
+ +
diff --git a/src/app/panels/statistics/module.html b/src/app/panels/statistics/module.html new file mode 100755 index 000000000..ff8c723ac --- /dev/null +++ b/src/app/panels/statistics/module.html @@ -0,0 +1,48 @@ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ItermCountMeanMaxMinStddev
+ +
{{row.term}}{{row.count}}{{row.mean | number:2}}{{row.max}}{{row.min}}{{row.stddev | number:2}}
+ +
+ + +
+
+
diff --git a/src/app/panels/statistics/module.js b/src/app/panels/statistics/module.js new file mode 100755 index 000000000..ce05949a1 --- /dev/null +++ b/src/app/panels/statistics/module.js @@ -0,0 +1,314 @@ +/* + ## Terms + + ### Parameters + * style :: A hash of css styles + * size :: top N + * arrangement :: How should I arrange the query results? 'horizontal' or 'vertical' + * chart :: Show a chart? 'none', 'bar', 'pie' + * donut :: Only applies to 'pie' charts. Punches a hole in the chart for some reason + * tilt :: Only 'pie' charts. Janky 3D effect. Looks terrible 90% of the time. + * lables :: Only 'pie' charts. Labels on the pie? + */ +define([ + 'angular', + 'app', + 'underscore', + 'jquery', + 'kbn', + 'angular-smart-table', + ], + function (angular, app, _, $, kbn) { + 'use strict'; + + var module = angular.module('kibana.panels.statistics', ['smart-table']); + app.useModule(module); + + module.controller('statistics', function($scope, $timeout, $filter, timer, querySrv, dashboard, filterSrv) { + $scope.panelMeta = { + exportfile: true, + editorTabs : [ + {title:'Queries', src:'app/partials/querySelect.html'} + ], + status : "Stable", + description : "Displays the results of a Solr facet as a pie chart, bar chart, or a table. Newly added functionality displays min/max/mean/sum of a stats field, faceted by the Solr facet field, again as a pie chart, bar chart or a table." + }; + + // Set and populate defaults + var _d = { + queries : { + mode : 'all', + ids : [], + query : '*:*', + custom : '' + }, + mode : 'statistic', // mode to tell which number will be used to plot the chart. + field : '', + stats_field : '', + decimal_points : 0, // The number of digits after the decimal point + exclude : [], + missing : false, + other : false, + size : 10000, + display:'block', + icon:"icon-caret-down", + sortBy : 'count', + threshold_first:3000, + threshold_second:5000, + order : 'descending', + style : { "font-size": '10pt'}, + fontsize:20, + linkage_id:'a', + donut : false, + tilt : false, + labels : true, + logAxis : false, + arrangement : 'horizontal', + chart : 'bar', + counter_pos : 'above', + exportSize : 10000, + lastColor : '', + spyable : true, + show_queries:true, + error : '', + chartColors : querySrv.colors, + refresh: { + enable: false, + interval: 2 + }, + itemsByPage: 10, + displayPage: 10, + }; + _.defaults($scope.panel,_d); + + + $scope.init = function () { + $scope.hits = 0; + //$scope.testMultivalued(); + + // Start refresh timer if enabled + if ($scope.panel.refresh.enable) { + $scope.set_timer($scope.panel.refresh.interval); + } + + $scope.$on('refresh',function(){ + $scope.get_data(); + }); + + $scope.get_data(); + }; + + $scope.testMultivalued = function() { + if($scope.panel.field && $scope.fields.typeList[$scope.panel.field] && $scope.fields.typeList[$scope.panel.field].schema.indexOf("M") > -1) { + $scope.panel.error = "Can't proceed with Multivalued field"; + return; + } + + if($scope.panel.stats_field && $scope.fields.typeList[$scope.panel.stats_field].schema.indexOf("M") > -1) { + $scope.panel.error = "Can't proceed with Multivalued field"; + return; + } + }; + + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; + + $scope.build_query = function(filetype, isForExport) { + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + } + var wt_json = '&wt=' + filetype; + var rows_limit = isForExport ? '&rows=0' : ''; // for terms, we do not need the actual response doc, so set rows=0 + var facet = ''; + + if ($scope.panel.mode === 'count') { + facet = '&facet=true&facet.field=' + $scope.panel.field + '&facet.limit=' + $scope.panel.size + '&facet.missing=true'; + } else { + facet = '&stats=true&stats.facet=' + $scope.panel.field + '&stats.field=' + $scope.panel.stats_field + '&facet.missing=true'; + } + facet += '&f.' + $scope.panel.field + '.facet.sort=' + ($scope.panel.sortBy || 'count'); + + var exclude_length = $scope.panel.exclude.length; + var exclude_filter = ''; + if(exclude_length > 0){ + for (var i = 0; i < exclude_length; i++) { + if($scope.panel.exclude[i] !== "") { + exclude_filter += '&fq=-' + $scope.panel.field +":"+ $scope.panel.exclude[i]; + } + } + } + return querySrv.getORquery() + wt_json + rows_limit + fq + exclude_filter + facet + ($scope.panel.queries.custom != null ? $scope.panel.queries.custom : ''); + }; + + $scope.exportfile = function(filetype) { + + var query = this.build_query(filetype, true); + + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + var request = $scope.sjs.Request().indices(dashboard.indices), + response; + + request.setQuery(query); + + response = request.doSearch(); + + // Populate scope when we have results + response.then(function(response) { + kbn.download_response(response, filetype, "terms"); + }); + }; + + $scope.set_timer = function(refresh_interval) { + $scope.panel.refresh.interval = refresh_interval; + if (_.isNumber($scope.panel.refresh.interval)) { + timer.cancel($scope.refresh_timer); + $scope.realtime(); + } else { + timer.cancel($scope.refresh_timer); + } + }; + + $scope.realtime = function() { + if ($scope.panel.refresh.enable) { + timer.cancel($scope.refresh_timer); + + $scope.refresh_timer = timer.register($timeout(function() { + $scope.realtime(); + $scope.get_data(); + }, $scope.panel.refresh.interval*1000)); + } else { + timer.cancel($scope.refresh_timer); + } + }; + + $scope.get_data = function() { + console.log("Get Data"); + // Make sure we have everything for the request to complete + if (dashboard.indices.length === 0) { + return; + } + + delete $scope.panel.error; + $scope.panelMeta.loading = true; + var request, results; + + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + + request = $scope.sjs.Request().indices(dashboard.indices); + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + + // Populate the inspector panel + $scope.inspector = angular.toJson(JSON.parse(request.toString()), true); + + var query = this.build_query('json', false); + + // Set the panel's query + $scope.panel.queries.query = query; + + request.setQuery(query); + results = request.doSearch(); + // Populate scope when we have results + results.then(function successCallback(response) { + var k = 0; + $scope.panelMeta.loading = false; + $scope.hits = response.response.numFound; + $scope.data = []; + $scope.yaxis_min = null; + // this callback will be called asynchronously + // when the response is available + $scope.yaxis_min = null; + console.log(response); + if ($scope.panel.mode === 'count') { + var temp_data = response.facet_counts.facet_fields[$scope.panel.field]; + for(var i=0; iFacet Pivot String Separated by commas
Facet Limit
- \ No newline at end of file + +
+
Linkage Effective
+
+ +
+ +
diff --git a/src/app/panels/sunburst/module.html b/src/app/panels/sunburst/module.html index 8eb1242fc..0011cb362 100644 --- a/src/app/panels/sunburst/module.html +++ b/src/app/panels/sunburst/module.html @@ -1,3 +1,5 @@
- +
+ +
diff --git a/src/app/panels/sunburst/module.js b/src/app/panels/sunburst/module.js index 0795d7f46..d5461ef46 100644 --- a/src/app/panels/sunburst/module.js +++ b/src/app/panels/sunburst/module.js @@ -17,12 +17,7 @@ define([ module.controller('sunburst', function ($scope, dashboard, querySrv, filterSrv) { $scope.panelMeta = { - modals: [{ - description: "Inspect", - icon: "icon-info-sign", - partial: "app/partials/inspector.html", - show: $scope.panel.spyable - }], + editorTabs: [{ title: 'Queries', src: 'app/partials/querySelect.html' @@ -38,6 +33,9 @@ define([ query: '*:*', custom: '' }, + display:'block', + linkage_id:'a', + icon:"icon-caret-down", facet_limit: 1000, // maximum number of rows returned from Solr spyable: true, show_queries: true, @@ -69,8 +67,19 @@ define([ } return t; }; + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; $scope.get_data = function () { + if(($scope.panel.linkage_id === dashboard.current.linkage_id)||dashboard.current.enable_linkage){ // Show progress by displaying a spinning wheel icon on panel $scope.panelMeta.loading = true; delete $scope.panel.error; @@ -123,7 +132,7 @@ define([ $scope.render(); }); - + } }; $scope.dash = dashboard; diff --git a/src/app/panels/table/editor.html b/src/app/panels/table/editor.html index dc1fe9044..d5289cf2e 100755 --- a/src/app/panels/table/editor.html +++ b/src/app/panels/table/editor.html @@ -1,16 +1,16 @@ -
-
-
-
Add Column
- - -
-
-
-
Columns Click to remove
- {{field}} +
+
+
+
Add Column
+ + +
+
+
+
Columns Click to remove
+ {{field}} +
-
-
Options
-
-
-
Header
-
-
-
Sorting
-
-
-
Sort
- - - -
-
-
Font Size
- -
-
-
Trim Factor Trim fields to this long divided by # of rows
- -
-
- -
-
-
Add Hyperlink Column Add a column that will contain hyperlinks to access another resources such as URLs.
- -
-
-
Link Column Header
- -
-
-
Display Links as Icons
- -
-
-
Column for Links
- +
Options
+
+
+
Header
+
+
+
Sorting
+
+
+
Sort
+ + + +
+
+
Font Size
+ +
+
+
Trim Factor Trim fields to this long divided by # of rows
+ +
-
-
-
-
Display Images Display images in column(s) that contain URLs to images.
- -
-
-
Image Field(s) Comma separated list of fields that contain image URL.
- -
-
-
Image Width For examples: auto, 85px, or 50%
- -
-
-
Image Height For examples: auto, 85px, or 50%
- +
+
+
Add Hyperlink Column Add a column that will contain hyperlinks to access another resources such as URLs.
+ +
+
+
Link Column Header
+ +
+
+
Display Links as Icons
+ +
+
+
Column for Links
+ +
-
-
-
Real-time (Auto-refresh)
-
- -
-
- - +
+
+
Display Images Display images in column(s) that contain URLs to images.
+ +
+
+
Image Field(s) Comma separated list of fields that contain image URL.
+ +
+
+
Image Width For examples: auto, 85px, or 50%
+ +
+
+
Image Height For examples: auto, 85px, or 50%
+ +
-
+
+
Linkage Effective
+
+ +
- + diff --git a/src/app/panels/table/fields.html b/src/app/panels/table/fields.html old mode 100644 new mode 100755 diff --git a/src/app/panels/table/module.html b/src/app/panels/table/module.html index a5659be3e..94a914582 100755 --- a/src/app/panels/table/module.html +++ b/src/app/panels/table/module.html @@ -6,7 +6,7 @@ overflow-x: scroll; } -
+

diff --git a/src/app/panels/table/module.js b/src/app/panels/table/module.js
index b4e2d7b1b..8dddbec3c 100755
--- a/src/app/panels/table/module.js
+++ b/src/app/panels/table/module.js
@@ -1,531 +1,503 @@
 /*
 
- ## Table
-
- ### Parameters
- * size :: Number of events per page to show
- * pages :: Number of pages to show. size * pages = number of cached events.
- Bigger = more memory usage byh the browser
- * offset :: Position from which to start in the array of hits
- * sort :: An array with 2 elements. sort[0]: field, sort[1]: direction ('asc' or 'desc')
- * style :: hash of css properties
- * fields :: columns to show in table
- * overflow :: 'height' or 'min-height' controls wether the row will expand (min-height) to
- to fit the table, or if the table will scroll to fit the row (height)
- * trimFactor :: If line is > this many characters, divided by the number of columns, trim it.
- * sortable :: Allow sorting?
- * spyable :: Show the 'eye' icon that reveals the last ES query for this panel
-
- */
+  ## Table
+
+  ### Parameters
+  * size :: Number of events per page to show
+  * pages :: Number of pages to show. size * pages = number of cached events.
+             Bigger = more memory usage byh the browser
+  * offset :: Position from which to start in the array of hits
+  * sort :: An array with 2 elements. sort[0]: field, sort[1]: direction ('asc' or 'desc')
+  * style :: hash of css properties
+  * fields :: columns to show in table
+  * overflow :: 'height' or 'min-height' controls wether the row will expand (min-height) to
+                to fit the table, or if the table will scroll to fit the row (height)
+  * trimFactor :: If line is > this many characters, divided by the number of columns, trim it.
+  * sortable :: Allow sorting?
+  * spyable :: Show the 'eye' icon that reveals the last ES query for this panel
+
+*/
 define([
-    'angular',
-    'app',
-    'underscore',
-    'kbn',
-    'moment'
-    // 'text!./pagination.html',
-    // 'text!partials/querySelect.html'
+  'angular',
+  'app',
+  'underscore',
+  'kbn',
+  'moment'
+  // 'text!./pagination.html',
+  // 'text!partials/querySelect.html'
 ],
 function (angular, app, _, kbn, moment) {
-    'use strict';
-
-    var module = angular.module('kibana.panels.table', []);
-    app.useModule(module);
-    module.controller('table', function ($rootScope, $scope, $timeout, timer, fields, querySrv, dashboard, filterSrv, solrSrv) {
-        $scope.panelMeta = {
-            modals: [
-                {
-                    description: "Inspect",
-                    icon: "icon-info-sign",
-                    partial: "app/partials/inspector.html",
-                    show: $scope.panel.spyable
-                }
-            ],
-            editorTabs: [
-                {
-                    title: 'Fields',
-                    src: 'app/panels/table/fields.html'
-                },
-                {
-                    title: 'Paging',
-                    src: 'app/panels/table/pagination.html'
-                },
-                {
-                    title: 'Queries',
-                    src: 'app/partials/querySelect.html'
-                }
-            ],
-            exportfile: true,
-            status: "Stable",
-            description: "A paginated table of records matching your query (including any filters that may have been applied). Click on a row to expand it and review all of the fields associated with that document. Provides the capability to export your result set to CSV, XML or JSON for further processing using other systems."
-        };
-
-        // Set and populate defaults
-        var _d = {
-            status: "Stable",
-            queries: {
-                mode: 'all',
-                ids: [],
-                query: '*:*',
-                basic_query: '',
-                custom: ''
-            },
-            size: 100, // Per page
-            pages: 5,   // Pages available
-            offset: 0,
-            sort: [], // By default, sorting is turned off for performance reason
-            sortable: false,
-            group: "default",
-            style: {'font-size': '9pt'},
-            overflow: 'min-height',
-            fields: [],
-            important_fields: [],
-            highlight: [],
-            header: true,
-            paging: true,
-            field_list: true,
-            trimFactor: 300,
-            normTimes: true,
-            spyable: true,
-            saveOption: 'json',
-            exportSize: 100,
-            exportAll: true,
-            displayLinkIcon: true,
-            imageFields: [],      // fields to be displayed as 
-            imgFieldWidth: 'auto', // width of  (if enabled)
-            imgFieldHeight: '85px', // height of  (if enabled)
-            show_queries: true,
-            maxNumCalcTopFields: 20, // Set the max number of fields for calculating top values
-            calcTopFieldValuesFromAllData: false, // false: calculate top field values from $scope.data
-                                                  // true: calculate from all data using Solr facet
-            refresh: {
-                enable: false,
-                interval: 2
-            }
-        };
-        _.defaults($scope.panel, _d);
-
-        $scope.init = function () {
-            $scope.Math = Math;
-            // Solr
-            $scope.sjs = $scope.sjs || sjsResource(dashboard.current.solr.server + dashboard.current.solr.core_name); // jshint ignore: line
-            $scope.$on('refresh', function () {
-                $scope.get_data();
-            });
-            $scope.panel.exportSize = $scope.panel.size * $scope.panel.pages;
-            $scope.fields = fields;
-
-            // Backward compatibility with old dashboards without important fields
-            // Set important fields to all fields if important fields array is empty
-            if (_.isEmpty($scope.panel.important_fields)) {
-                $scope.panel.important_fields = fields.list;
-            }
-
-            // Start refresh timer if enabled
-            if ($scope.panel.refresh.enable) {
-                $scope.set_timer($scope.panel.refresh.interval);
-            }
-
-            $scope.get_data();
-        };
-
-        $scope.percent = kbn.to_percent;
-
-        $scope.set_timer = function (refresh_interval) {
-            $scope.panel.refresh.interval = refresh_interval;
-            if (_.isNumber($scope.panel.refresh.interval)) {
-                timer.cancel($scope.refresh_timer);
-                $scope.realtime();
+  'use strict';
+
+  var module = angular.module('kibana.panels.table', []);
+  app.useModule(module);
+  module.controller('table', function($rootScope, $scope, fields, querySrv, dashboard, filterSrv, solrSrv) {
+    $scope.panelMeta = {
+
+      editorTabs : [
+        {
+          title:'Fields',
+          src: 'app/panels/table/fields.html'
+        },
+        {
+          title:'Paging',
+          src: 'app/panels/table/pagination.html'
+        },
+        {
+          title:'Queries',
+          src: 'app/partials/querySelect.html'
+        }
+      ],
+      exportfile: true,
+      status: "Stable",
+      description: "A paginated table of records matching your query (including any filters that may have been applied). Click on a row to expand it and review all of the fields associated with that document. Provides the capability to export your result set to CSV, XML or JSON for further processing using other systems."
+    };
+
+    // Set and populate defaults
+    var _d = {
+      status  : "Stable",
+      queries     : {
+        mode        : 'all',
+        ids         : [],
+        query       : '*:*',
+        basic_query : '',
+        custom      : ''
+      },
+      size    : 100, // Per page
+      pages   : 5,   // Pages available
+      offset  : 0,
+      sort    : [], // By default, sorting is turned off for performance reason
+      sortable: false,
+      group   : "default",
+      style   : {'font-size': '9pt'},
+      overflow: 'min-height',
+      fields  : [],
+      important_fields : [],
+      highlight : [],
+      header  : true,
+      paging  : true,
+        display:'block',
+        icon:"icon-caret-down",
+
+      field_list: true,
+      linkage_enable:true,
+      trimFactor: 300,
+      normTimes : true,
+      spyable : true,
+      saveOption : 'json',
+      exportSize: 100,
+      exportAll: true,
+      displayLinkIcon: true,
+      imageFields : [],      // fields to be displayed as 
+      imgFieldWidth: 'auto', // width of  (if enabled)
+      imgFieldHeight: '85px', // height of  (if enabled)
+      show_queries: true,
+      maxNumCalcTopFields: 20, // Set the max number of fields for calculating top values
+      calcTopFieldValuesFromAllData: false // false: calculate top field values from $scope.data
+                                           // true: calculate from all data using Solr facet
+    };
+    _.defaults($scope.panel,_d);
+
+    $scope.percent = kbn.to_percent;
+
+    $scope.init = function () {
+      $scope.Math = Math;
+      // Solr
+      $scope.sjs = $scope.sjs || sjsResource(dashboard.current.solr.server + dashboard.current.solr.core_name); // jshint ignore: line
+      $scope.$on('refresh',function(){$scope.get_data();});
+      $scope.panel.exportSize = $scope.panel.size * $scope.panel.pages;
+      $scope.fields = fields;
+      $scope.get_data();
+    };
+      $scope.display=function() {
+          if($scope.panel.display=='none'){
+              $scope.panel.display='block';
+              $scope.panel.icon="icon-caret-down";
+
+
+          }else{
+              $scope.panel.display='none';
+              $scope.panel.icon="icon-caret-up";
+          }
+      };
+    $scope.toggle_micropanel = function(field,groups) {
+      var docs = _.map($scope.data,function(_d){return _d.kibana._source;});
+      var topFieldValues = {};
+      var totalcount = 0;
+
+      if (!$scope.panel.calcTopFieldValuesFromAllData) {
+        topFieldValues = kbn.top_field_values(docs,field,10,groups);
+        totalcount = _.countBy(docs,function(doc){return _.contains(_.keys(doc),field);})['true'];
+      } else {
+        topFieldValues = solrSrv.getTopFieldValues(field);
+        totalcount = topFieldValues.totalcount;
+      }
+
+      $scope.micropanel = {
+        field: field,
+        grouped: groups,
+        values : topFieldValues.counts,
+        hasArrays : topFieldValues.hasArrays,
+        related : kbn.get_related_fields(docs,field),
+        count: totalcount
+      };
+    };
+
+    $scope.micropanelColor = function(index) {
+      var _c = ['bar-success','bar-warning','bar-danger','bar-info','bar-primary'];
+      return index > _c.length ? '' : _c[index];
+    };
+
+    $scope.set_sort = function(field) {
+      if($scope.panel.sort[0] === field) {
+        $scope.panel.sort[1] = $scope.panel.sort[1] === 'asc' ? 'desc' : 'asc';
+      } else {
+        $scope.panel.sort[0] = field;
+      }
+      $scope.get_data();
+    };
+
+    $scope.toggle_field = function(field) {
+      if (_.indexOf($scope.panel.fields, field) > -1) {
+        $scope.panel.fields = _.without($scope.panel.fields, field);
+      } else if (_.indexOf(fields.list, field) > -1) {
+        $scope.panel.fields.push(field);
+      } else {
+        return;
+      }
+    };
+
+    // Toggle important field that will appear to the left of table panel
+    $scope.toggle_important_field = function(field) {
+      if (_.indexOf($scope.panel.important_fields,field) > -1) {
+        $scope.panel.important_fields = _.without($scope.panel.important_fields,field);
+      } else {
+        $scope.panel.important_fields.push(field);
+      }
+    };
+
+    $scope.toggle_highlight = function(field) {
+      if (_.indexOf($scope.panel.highlight,field) > -1) {
+        $scope.panel.highlight = _.without($scope.panel.highlight,field);
+      } else {
+        $scope.panel.highlight.push(field);
+      }
+    };
+
+    $scope.toggle_details = function(row) {
+      row.kibana.details = row.kibana.details ? false : true;
+      row.kibana.view = row.kibana.view || 'table';
+      //row.kibana.details = !row.kibana.details ? $scope.without_kibana(row) : false;
+    };
+
+    $scope.page = function(page) {
+      $scope.panel.offset = page*$scope.panel.size;
+      $scope.get_data();
+    };
+
+    $scope.build_search = function(field,value,negate) {
+        if($scope.panel.linkage_enable){
+        var query;
+        // This needs to be abstracted somewhere
+        if (_.isArray(value)) {
+            // TODO: I don't think Solr has "AND" operator in query.
+            query = "(" + _.map(value, function (v) {
+                    return angular.toJson(v);
+                }).join(" AND ") + ")";
+        } else if (_.isUndefined(value)) {
+            query = '*:*';
+            negate = !negate;
+        } else {
+            query = angular.toJson(value);
+        }
+        // TODO: Need to take a look here, not sure if need change.
+        filterSrv.set({type: 'field', field: field, query: query, mandate: (negate ? 'mustNot' : 'must')});
+
+        $scope.panel.offset = 0;
+        dashboard.current.enable_linkage =false;
+        dashboard.refresh();
+    }
+    };
+
+    $scope.fieldExists = function(field,mandate) {
+      // TODO: Need to take a look here.
+      filterSrv.set({type:'exists',field:field,mandate:mandate});
+      dashboard.refresh();
+    };
+
+    $scope.get_data = function(segment,query_id) {
+        if($scope.panel.linkage_enable||dashboard.current.enable_linkage){
+        $scope.panel.error = false;
+        delete $scope.panel.error;
+
+        // Make sure we have everything for the request to complete
+        if (dashboard.indices.length === 0) {
+            return;
+        }
+        $scope.panelMeta.loading = true;
+        $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries);
+
+        // Calculate top field values
+        if ($scope.panel.calcTopFieldValuesFromAllData) {
+            // Make sure we are not calculating too much facet fields.
+            if ($scope.panel.important_fields.length > $scope.panel.maxNumCalcTopFields) {
+                alert('You cannot specify more than ' + $scope.panel.maxNumCalcTopFields + ' fields for the calculation. Please select less fields.');
             } else {
-                timer.cancel($scope.refresh_timer);
+                solrSrv.calcTopFieldValues($scope.panel.important_fields);
             }
-        };
-
-        $scope.realtime = function () {
-            if ($scope.panel.refresh.enable) {
-                timer.cancel($scope.refresh_timer);
+        }
+
+        // What this segment is for? => to select which indices to query.
+        var _segment = _.isUndefined(segment) ? 0 : segment;
+        $scope.segment = _segment;
+        $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name);
+        var request = $scope.sjs.Request().indices(dashboard.indices[_segment]);
+        $scope.panel_request = request;
+
+        var fq = '';
+        if (filterSrv.getSolrFq()) {
+            fq = '&' + filterSrv.getSolrFq();
+        }
+        var query_size = $scope.panel.size * $scope.panel.pages;
+        var wt_json = '&wt=json';
+        var rows_limit;
+        var sorting = '';
+
+        if ($scope.panel.sort[0] !== undefined && $scope.panel.sort[1] !== undefined && $scope.panel.sortable) {
+            sorting = '&sort=' + $scope.panel.sort[0] + ' ' + $scope.panel.sort[1];
+        }
+
+        // set the size of query result
+        if (query_size !== undefined && query_size !== 0) {
+            rows_limit = '&rows=' + query_size;
+        } else { // default
+            rows_limit = '&rows=25';
+        }
+
+        // Set the panel's query
+        $scope.panel.queries.basic_query = querySrv.getORquery() + fq + sorting;
+        $scope.panel.queries.query = $scope.panel.queries.basic_query + wt_json + rows_limit;
+
+        // Set the additional custom query
+        if ($scope.panel.queries.custom != null) {
+            request = request.setQuery($scope.panel.queries.query + $scope.panel.queries.custom);
+        } else {
+            request = request.setQuery($scope.panel.queries.query);
+        }
+
+        var results = request.doSearch();
+
+        // Populate scope when we have results
+        results.then(function (results) {
+            $scope.panel.offset = 0;
+            $scope.panelMeta.loading = false;
 
-                $scope.refresh_timer = timer.register($timeout(function () {
-                    $scope.realtime();
-                    $scope.get_data();
-                }, $scope.panel.refresh.interval * 1000));
-            } else {
-                timer.cancel($scope.refresh_timer);
-            }
-        };
-
-        $scope.toggle_micropanel = function (field, groups) {
-            var docs = _.map($scope.data, function (_d) {
-                return _d.kibana._source;
-            });
-            var topFieldValues = {};
-            var totalcount = 0;
-
-            if (!$scope.panel.calcTopFieldValuesFromAllData) {
-                topFieldValues = kbn.top_field_values(docs, field, 10, groups);
-                totalcount = _.countBy(docs, function (doc) {
-                    return _.contains(_.keys(doc), field);
-                })['true'];
+            if (_segment === 0) {
+                $scope.hits = 0;
+                $scope.data = [];
+                query_id = $scope.query_id = new Date().getTime();
             } else {
-                topFieldValues = solrSrv.getTopFieldValues(field);
-                totalcount = topFieldValues.totalcount;
+                // Fix BUG with wrong total event count.
+                $scope.data = [];
             }
 
-            $scope.micropanel = {
-                field: field,
-                grouped: groups,
-                values: topFieldValues.counts,
-                hasArrays: topFieldValues.hasArrays,
-                related: kbn.get_related_fields(docs, field),
-                count: totalcount
-            };
-        };
-
-        $scope.micropanelColor = function (index) {
-            var _c = ['bar-success', 'bar-warning', 'bar-danger', 'bar-info', 'bar-primary'];
-            return index > _c.length ? '' : _c[index];
-        };
-
-        $scope.set_sort = function (field) {
-            if ($scope.panel.sort[0] === field) {
-                $scope.panel.sort[1] = $scope.panel.sort[1] === 'asc' ? 'desc' : 'asc';
-            } else {
-                $scope.panel.sort[0] = field;
-            }
-            $scope.get_data();
-        };
-
-        $scope.toggle_field = function (field) {
-            if (_.indexOf($scope.panel.fields, field) > -1) {
-                $scope.panel.fields = _.without($scope.panel.fields, field);
-            } else if (_.indexOf(fields.list, field) > -1) {
-                $scope.panel.fields.push(field);
-            } else {
+            // Check for error and abort if found
+            if (!(_.isUndefined(results.error))) {
+                $scope.panel.error = $scope.parse_error(results.error.msg); // There's also results.error.code
                 return;
             }
-        };
 
-        // Toggle important field that will appear to the left of table panel
-        $scope.toggle_important_field = function (field) {
-            if (_.indexOf($scope.panel.important_fields, field) > -1) {
-                $scope.panel.important_fields = _.without($scope.panel.important_fields, field);
+            // Check that we're still on the same query, if not stop
+            if ($scope.query_id === query_id) {
+                $scope.data = $scope.data.concat(_.map(results.response.docs, function (hit) {
+                    var _h = _.clone(hit);
+                    _h.kibana = {
+                        _source: kbn.flatten_json(hit),
+                        highlight: kbn.flatten_json(hit.highlight || {})
+                    };
+
+                    return _h;
+                }));
+
+                // Solr does not need to accumulate hits count because it can get total count
+                // from a single faceted query.
+                $scope.hits = results.response.numFound;
+
+                // Keep only what we need for the set
+                $scope.data = $scope.data.slice(0, $scope.panel.size * $scope.panel.pages);
+
+                // Dynamically display only non-empty fields on the field list (left side)
+                $scope.panel.important_fields = [];
+                _.each($scope.data, function (doc) {
+                    $scope.panel.important_fields = _.union(_.keys(doc.kibana._source));
+                });
             } else {
-                $scope.panel.important_fields.push(field);
-            }
-        };
-
-        $scope.toggle_highlight = function (field) {
-            if (_.indexOf($scope.panel.highlight, field) > -1) {
-                $scope.panel.highlight = _.without($scope.panel.highlight, field);
-            } else {
-                $scope.panel.highlight.push(field);
-            }
-        };
-
-        $scope.toggle_details = function (row) {
-            row.kibana.details = row.kibana.details ? false : true;
-            row.kibana.view = row.kibana.view || 'table';
-            //row.kibana.details = !row.kibana.details ? $scope.without_kibana(row) : false;
-        };
-
-        $scope.page = function (page) {
-            $scope.panel.offset = page * $scope.panel.size;
-            $scope.get_data();
-        };
-
-        $scope.build_search = function (field, value, negate) {
-            var query;
-            // This needs to be abstracted somewhere
-            if (_.isArray(value)) {
-                // TODO: I don't think Solr has "AND" operator in query.
-                query = "(" + _.map(value, function (v) {
-                        return angular.toJson(v);
-                    }).join(" AND ") + ")";
-            } else if (_.isUndefined(value)) {
-                query = '*:*';
-                negate = !negate;
-            } else {
-                query = angular.toJson(value);
-            }
-            // TODO: Need to take a look here, not sure if need change.
-            filterSrv.set({type: 'field', field: field, query: query, mandate: (negate ? 'mustNot' : 'must')});
-
-            $scope.panel.offset = 0;
-            dashboard.refresh();
-        };
-
-        $scope.fieldExists = function (field, mandate) {
-            // TODO: Need to take a look here.
-            filterSrv.set({type: 'exists', field: field, mandate: mandate});
-            dashboard.refresh();
-        };
-
-        $scope.get_data = function (segment, query_id) {
-            $scope.panel.error = false;
-            delete $scope.panel.error;
-            // Make sure we have everything for the request to complete
-            if (dashboard.indices.length === 0) {
                 return;
             }
-            $scope.panelMeta.loading = true;
-            $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries);
-
-            // Calculate top field values
-            if ($scope.panel.calcTopFieldValuesFromAllData) {
-                // Make sure we are not calculating too much facet fields.
-                if ($scope.panel.important_fields.length > $scope.panel.maxNumCalcTopFields) {
-                    alert('You cannot specify more than ' + $scope.panel.maxNumCalcTopFields + ' fields for the calculation. Please select less fields.');
-                } else {
-                    solrSrv.calcTopFieldValues($scope.panel.important_fields);
-                }
-            }
-
-            // What this segment is for? => to select which indices to query.
-            var _segment = _.isUndefined(segment) ? 0 : segment;
-            $scope.segment = _segment;
-            $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name);
-            var request = $scope.sjs.Request().indices(dashboard.indices[_segment]);
-            $scope.panel_request = request;
-
-            var fq = '';
-            if (filterSrv.getSolrFq()) {
-                fq = '&' + filterSrv.getSolrFq();
-            }
-            var query_size = $scope.panel.size * $scope.panel.pages;
-            var wt_json = '&wt=json';
-            var rows_limit;
-            var sorting = '';
 
-            if ($scope.panel.sort[0] !== undefined && $scope.panel.sort[1] !== undefined && $scope.panel.sortable) {
-                sorting = '&sort=' + $scope.panel.sort[0] + ' ' + $scope.panel.sort[1];
-            }
-
-            // set the size of query result
-            if (query_size !== undefined && query_size !== 0) {
-                rows_limit = '&rows=' + query_size;
-            } else { // default
-                rows_limit = '&rows=25';
-            }
-
-            // Set the panel's query
-            $scope.panel.queries.basic_query = querySrv.getORquery() + fq + sorting;
-            $scope.panel.queries.query = $scope.panel.queries.basic_query + wt_json + rows_limit;
-
-            // Set the additional custom query
-            if ($scope.panel.queries.custom != null) {
-                request = request.setQuery($scope.panel.queries.query + $scope.panel.queries.custom);
-            } else {
-                request = request.setQuery($scope.panel.queries.query);
-            }
-
-            var results = request.doSearch();
-
-            // Populate scope when we have results
-            results.then(function (results) {
-                $scope.panel.offset = 0;
-                $scope.panelMeta.loading = false;
-
-                if (_segment === 0) {
-                    $scope.hits = 0;
-                    $scope.data = [];
-                    query_id = $scope.query_id = new Date().getTime();
-                } else {
-                    // Fix BUG with wrong total event count.
-                    $scope.data = [];
-                }
-
-                // Check for error and abort if found
-                if (!(_.isUndefined(results.error))) {
-                    $scope.panel.error = $scope.parse_error(results.error.msg); // There's also results.error.code
-                    return;
-                }
-
-                // Check that we're still on the same query, if not stop
-                if ($scope.query_id === query_id) {
-                    $scope.data = $scope.data.concat(_.map(results.response.docs, function (hit) {
-                        var _h = _.clone(hit);
-                        _h.kibana = {
-                            _source: kbn.flatten_json(hit),
-                            highlight: kbn.flatten_json(hit.highlight || {})
-                        };
-
-                        return _h;
-                    }));
-
-                    // Solr does not need to accumulate hits count because it can get total count
-                    // from a single faceted query.
-                    $scope.hits = results.response.numFound;
-
-                    // Keep only what we need for the set
-                    $scope.data = $scope.data.slice(0, $scope.panel.size * $scope.panel.pages);
-
-                    // TODO $scope.panel.import_fields should not be cleared, because it contains user's preference for which fields to show.
-                    // Dynamically display only non-empty fields on the field list (left side)
-                    // $scope.panel.important_fields = [];
-                    // _.each($scope.data, function (doc) {
-                    //     $scope.panel.important_fields = _.union(_.keys(doc.kibana._source));
-                    // });
-                } else {
-                    return;
-                }
-
-                // If we're not sorting in reverse chrono order, query every index for
-                // size*pages results
-                // Otherwise, only get size*pages results then stop querying
-                if (($scope.data.length < $scope.panel.size * $scope.panel.pages || !((_.contains(filterSrv.timeField(), $scope.panel.sort[0])) && $scope.panel.sort[1] === 'desc')) &&
-                    _segment + 1 < dashboard.indices.length) {
-                    $scope.get_data(_segment + 1, $scope.query_id);
-                }
-            });
-        };
-
-        $scope.exportfile = function (filetype) {
-            var omitHeader = '&omitHeader=true';
-            var rows_limit = '&rows=' + ($scope.panel.exportSize || ($scope.panel.size * $scope.panel.pages));
-            var fl = '';
-            if (!$scope.panel.exportAll) {
-                fl = '&fl=';
-                for (var i = 0; i < $scope.panel.fields.length; i++) {
-                    fl += $scope.panel.fields[i] + (i !== $scope.panel.fields.length - 1 ? ',' : '');
-                }
-            }
-            var exportQuery = $scope.panel.queries.basic_query + '&wt=' + filetype + omitHeader + rows_limit + fl;
-            var request = $scope.panel_request;
-
-            if ($scope.panel.queries.custom != null) {
-                request = request.setQuery(exportQuery + $scope.panel.queries.custom);
-            } else {
-                request = request.setQuery(exportQuery);
-            }
-
-            var response = request.doSearch();
-
-            response.then(function (response) {
-                kbn.download_response(response, filetype, "table");
-            });
-        };
-
-        $scope.facet_label = function (key) {
-            return filterSrv.translateLanguageKey("facet", key, dashboard.current);
-        };
-
-        $scope.populate_modal = function (request) {
-            $scope.inspector = angular.toJson(JSON.parse(request.toString()), true);
-        };
-
-        $scope.without_kibana = function (row) {
-            var _c = _.clone(row);
-            delete _c.kibana;
-            return _c;
-        };
-
-        $scope.set_refresh = function (state) {
-            $scope.refresh = state;
-        };
-
-        $scope.close_edit = function () {
-            // Start refresh timer if enabled
-            if ($scope.panel.refresh.enable) {
-                $scope.set_timer($scope.panel.refresh.interval);
-            }
-            if ($scope.refresh) {
-                $scope.get_data();
-            }
-            $scope.refresh = false;
-        };
-
-        $scope.locate = function (obj, path) {
-            path = path.split('.');
-            var arrayPattern = /(.+)\[(\d+)\]/;
-            for (var i = 0; i < path.length; i++) {
-                var match = arrayPattern.exec(path[i]);
-                if (match) {
-                    obj = obj[match[1]][parseInt(match[2], 10)];
-                } else {
-                    obj = obj[path[i]];
-                }
-            }
-            return obj;
-        };
-    });
-
-    // This also escapes some xml sequences
-    module.filter('tableHighlight', function () {
-        return function (text) {
-            if (!_.isUndefined(text) && !_.isNull(text) && text.toString().length > 0) {
-                return text.toString().replace(/&/g, '&').replace(//g, '>').replace(/\r?\n/g, '
').replace(/@start-highlight@/g, '').replace(/@end-highlight@/g, ''); - } - return ''; - }; - }); - - module.filter('tableTruncate', function () { - return function (text, length, factor, field, imageFields) { - // If image field, then do not truncate, otherwise we will get invalid URIs. - if (typeof field !== 'undefined' && imageFields.length > 0 && _.contains(imageFields, field)) { - return text; - } - - if (!_.isUndefined(text) && !_.isNull(text) && text.toString().length > 0) { - return text.length > length / factor ? text.substr(0, length / factor) + '...' : text; - } - return ''; - }; - }); - - module.filter('tableJson', function () { - var json; - return function (text, prettyLevel) { - if (!_.isUndefined(text) && !_.isNull(text) && text.toString().length > 0) { - json = angular.toJson(text, prettyLevel > 0 ? true : false); - json = json.replace(/&/g, '&').replace(//g, '>'); - if (prettyLevel > 1) { - /* jshint maxlen: false */ - json = json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) { - var cls = 'number'; - if (/^"/.test(match)) { - if (/:$/.test(match)) { - cls = 'key strong'; - } else { - cls = ''; - } - } else if (/true|false/.test(match)) { - cls = 'boolean'; - } else if (/null/.test(match)) { - cls = 'null'; - } - return '' + match + ''; - }); - } - return json; - } - return ''; - }; - }); - - // WIP - module.filter('tableFieldFormat', function (fields) { - return function (text, field, event, scope) { - var type; - if ( - !_.isUndefined(fields.mapping[event._index]) && !_.isUndefined(fields.mapping[event._index][event._type]) - ) { - type = fields.mapping[event._index][event._type][field]['type']; - if (type === 'date' && scope.panel.normTimes) { - return moment(text).format('YYYY-MM-DD HH:mm:ss'); - } + // If we're not sorting in reverse chrono order, query every index for + // size*pages results + // Otherwise, only get size*pages results then stop querying + if (($scope.data.length < $scope.panel.size * $scope.panel.pages || + !((_.contains(filterSrv.timeField(), $scope.panel.sort[0])) && $scope.panel.sort[1] === 'desc')) && + _segment + 1 < dashboard.indices.length) { + $scope.get_data(_segment + 1, $scope.query_id); } - return text; - }; - }); - - // This filter will check the input field to see if it should be displayed as - module.filter('tableDisplayImageField', function () { - return function (data, field, imageFields, width, height) { - if (typeof field !== 'undefined' && imageFields.length > 0 && _.contains(imageFields, field)) { - return ''; + }); + } + }; + + $scope.exportfile = function(filetype) { + var omitHeader = '&omitHeader=true'; + var rows_limit = '&rows=' + ($scope.panel.exportSize || ($scope.panel.size * $scope.panel.pages)); + var fl = ''; + + if (! $scope.panel.exportAll) { + fl = '&fl='; + for(var i = 0; i < $scope.panel.fields.length; i++) { + fl += $scope.panel.fields[i] + (i !== $scope.panel.fields.length - 1 ? ',' : ''); + } + } + var exportQuery = $scope.panel.queries.basic_query + '&wt=' + filetype + omitHeader + rows_limit + fl; + var request = $scope.panel_request; + + if ($scope.panel.queries.custom != null) { + request = request.setQuery(exportQuery + $scope.panel.queries.custom); + } else { + request = request.setQuery(exportQuery); + } + + var response = request.doSearch(); + + response.then(function(response) { + kbn.download_response(response, filetype, "table"); + }); + }; + + $scope.facet_label = function(key) { + return filterSrv.translateLanguageKey("facet", key, dashboard.current); + }; + + $scope.populate_modal = function(request) { + $scope.inspector = angular.toJson(JSON.parse(request.toString()),true); + }; + + $scope.without_kibana = function (row) { + var _c = _.clone(row); + delete _c.kibana; + return _c; + }; + + $scope.set_refresh = function (state) { + $scope.refresh = state; + }; + + $scope.close_edit = function() { + if($scope.refresh) { + $scope.get_data(); + } + $scope.refresh = false; + }; + + $scope.locate = function(obj, path) { + path = path.split('.'); + var arrayPattern = /(.+)\[(\d+)\]/; + for (var i = 0; i < path.length; i++) { + var match = arrayPattern.exec(path[i]); + if (match) { + obj = obj[match[1]][parseInt(match[2],10)]; + } else { + obj = obj[path[i]]; + } + } + return obj; + }; + }); + + // This also escapes some xml sequences + module.filter('tableHighlight', function() { + return function(text) { + if (!_.isUndefined(text) && !_.isNull(text) && text.toString().length > 0) { + return text.toString(). + replace(/&/g, '&'). + replace(//g, '>'). + replace(/\r?\n/g, '
'). + replace(/@start-highlight@/g, ''). + replace(/@end-highlight@/g, ''); + } + return ''; + }; + }); + + module.filter('tableTruncate', function() { + return function(text,length,factor,field,imageFields) { + // If image field, then do not truncate, otherwise we will get invalid URIs. + if (typeof field !== 'undefined' && imageFields.length>0 && _.contains(imageFields, field)) { + return text; + } + + if (!_.isUndefined(text) && !_.isNull(text) && text.toString().length > 0) { + return text.length > length/factor ? text.substr(0,length/factor)+'...' : text; + } + return ''; + }; + }); + + module.filter('tableJson', function() { + var json; + return function(text,prettyLevel) { + if (!_.isUndefined(text) && !_.isNull(text) && text.toString().length > 0) { + json = angular.toJson(text,prettyLevel > 0 ? true : false); + json = json.replace(/&/g, '&').replace(//g, '>'); + if(prettyLevel > 1) { + /* jshint maxlen: false */ + json = json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) { + var cls = 'number'; + if (/^"/.test(match)) { + if (/:$/.test(match)) { + cls = 'key strong'; + } else { + cls = ''; + } + } else if (/true|false/.test(match)) { + cls = 'boolean'; + } else if (/null/.test(match)) { + cls = 'null'; } - return data; - }; - }); + return '' + match + ''; + }); + } + return json; + } + return ''; + }; + }); + + // WIP + module.filter('tableFieldFormat', function(fields){ + return function(text,field,event,scope) { + var type; + if( + !_.isUndefined(fields.mapping[event._index]) && + !_.isUndefined(fields.mapping[event._index][event._type]) + ) { + type = fields.mapping[event._index][event._type][field]['type']; + if(type === 'date' && scope.panel.normTimes) { + return moment(text).format('YYYY-MM-DD HH:mm:ss'); + } + } + return text; + }; + }); + + // This filter will check the input field to see if it should be displayed as + module.filter('tableDisplayImageField', function() { + return function(data, field, imageFields, width, height) { + if (typeof field !== 'undefined' && imageFields.length>0 && _.contains(imageFields, field)) { + return ''; + } + return data; + }; + }); }); diff --git a/src/app/panels/tagcloud/editor.html b/src/app/panels/tagcloud/editor.html old mode 100755 new mode 100644 index a49521c75..9055da143 --- a/src/app/panels/tagcloud/editor.html +++ b/src/app/panels/tagcloud/editor.html @@ -17,17 +17,27 @@
+
+
+
-
\ No newline at end of file +
+
+
Linkage Effective
+
+ +
+ +
diff --git a/src/app/panels/tagcloud/module.html b/src/app/panels/tagcloud/module.html old mode 100755 new mode 100644 index 91bab1d98..0d4af9222 --- a/src/app/panels/tagcloud/module.html +++ b/src/app/panels/tagcloud/module.html @@ -1,3 +1,3 @@
-
+
diff --git a/src/app/panels/tagcloud/module.js b/src/app/panels/tagcloud/module.js old mode 100755 new mode 100644 index fd8208f30..2978769da --- a/src/app/panels/tagcloud/module.js +++ b/src/app/panels/tagcloud/module.js @@ -14,10 +14,10 @@ define([ 'jquery', 'kbn', 'd3', - './stopWords', - './d3.layout.cloud' + './d3.layout.cloud', + './stopWords' ], - function(angular, app, _, $, kbn, d3, stopwords) { + function(angular, app, _, $, kbn, d3) { 'use strict'; var module = angular.module('kibana.panels.tagcloud', []); @@ -25,12 +25,7 @@ define([ module.controller('tagcloud', function($scope, querySrv, dashboard, filterSrv) { $scope.panelMeta = { - modals: [{ - description: "Inspect", - icon: "icon-info-sign", - partial: "app/partials/inspector.html", - show: $scope.panel.spyable - }], + editorTabs: [{ title: 'Queries', src: 'app/partials/querySelect.html' @@ -49,6 +44,9 @@ define([ }, field: '', size: 10, + linkage_id:'a', + display:'block', + icon:"icon-caret-down", alignment: 'vertical and horizontal', fontScale: 1, ignoreStopWords: false, @@ -65,96 +63,108 @@ define([ }); $scope.get_data(); }; + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; - $scope.get_data = function() { - // Make sure we have everything for the request to complete - if (dashboard.indices.length === 0) { - return; - } - delete $scope.panel.error; - $scope.panelMeta.loading = true; - var request, results; - - $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); - request = $scope.sjs.Request().indices(dashboard.indices); - $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; + $scope.get_data = function() { + if(($scope.panel.linkage_id === dashboard.current.linkage_id)||dashboard.current.enable_linkage){ + // Make sure we have everything for the request to complete + if (dashboard.indices.length === 0) { + return; + } + delete $scope.panel.error; + $scope.panelMeta.loading = true; + var request, results; - // Populate the inspector panel - $scope.inspector = angular.toJson(JSON.parse(request.toString()), true); + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); - // Build Solr query - var fq = ''; - if (filterSrv.getSolrFq()) { - fq = '&' + filterSrv.getSolrFq(); - } - var wt_json = '&wt=json'; - var rows_limit = '&rows=0'; // for terms, we do not need the actual response doc, so set rows=0 - var facet = '&facet=true&facet.field=' + $scope.panel.field + '&facet.limit=' + $scope.panel.size; - - // Set the panel's query - $scope.panel.queries.query = querySrv.getORquery() + wt_json + rows_limit + fq + facet; - - // Set the additional custom query - if ($scope.panel.queries.custom != null) { - request = request.setQuery($scope.panel.queries.query + $scope.panel.queries.custom); - } else { - request = request.setQuery($scope.panel.queries.query); - } + request = $scope.sjs.Request().indices(dashboard.indices); + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); - results = request.doSearch(); + // Populate the inspector panel + $scope.inspector = angular.toJson(JSON.parse(request.toString()), true); - // Populate scope when we have results - results.then(function(results) { - // Check for error and abort if found - if (!(_.isUndefined(results.error))) { - $scope.panel.error = $scope.parse_error(results.error.msg); - return; + // Build Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + } + var wt_json = '&wt=json'; + var rows_limit = '&rows=0'; // for terms, we do not need the actual response doc, so set rows=0 + var facet = '&facet=true&facet.field=' + $scope.panel.field + '&facet.limit=' + $scope.panel.size; + + // Set the panel's query + $scope.panel.queries.query = querySrv.getORquery() + wt_json + rows_limit + fq + facet; + + // Set the additional custom query + if ($scope.panel.queries.custom != null) { + request = request.setQuery($scope.panel.queries.query + $scope.panel.queries.custom); + } else { + request = request.setQuery($scope.panel.queries.query); } - var sum = 0; -// var k = 0; - var missing = 0; - $scope.panelMeta.loading = false; - $scope.hits = results.response.numFound; - $scope.data = []; - $scope.maxRatio = 0; - - - $scope.yaxis_min = 0; - _.each(results.facet_counts.facet_fields, function(v) { - for (var i = 0; i < v.length; i++) { - var term = v[i]; - i++; - var count = v[i]; - sum += count; - - // if ignoreStopWords is enabled, skip this term. - if ($scope.panel.ignoreStopWords && stopwords.indexOf(term.toLowerCase()) > -1) { - continue; - } + results = request.doSearch(); - if (term === null) { - missing = count; - } else { - // if count = 0, do not add it to the chart, just skip it - if (count === 0) { - continue; - } - var slice = { - label: term, - data: count, - actions: true - }; - if (count / $scope.hits > $scope.maxRatio) { - $scope.maxRatio = count / $scope.hits; - } - $scope.data.push(slice); + // Populate scope when we have results + results.then(function (results) { + // Check for error and abort if found + if (!(_.isUndefined(results.error))) { + $scope.panel.error = $scope.parse_error(results.error.msg); + return; } - } + + var sum = 0; +// var k = 0; + var missing = 0; + $scope.panelMeta.loading = false; + $scope.hits = results.response.numFound; + $scope.data = []; + $scope.maxRatio = 0; + + + $scope.yaxis_min = 0; + _.each(results.facet_counts.facet_fields, function (v) { + for (var i = 0; i < v.length; i++) { + var term = v[i]; + i++; + var count = v[i]; + sum += count; + + // if ignoreStopWords is enabled, skip this term. + if ($scope.panel.ignoreStopWords && (stopwords.indexOf(term.toLowerCase()) > -1)) { + continue; + } + + if (term === null) { + missing = count; + } else { + // if count = 0, do not add it to the chart, just skip it + if (count === 0) { + continue; + } + var slice = { + label: term, + data: count, + actions: true + }; + if (count / $scope.hits > $scope.maxRatio) { + $scope.maxRatio = count / $scope.hits; + } + $scope.data.push(slice); + } + } + }); + $scope.$emit('render'); }); - $scope.$emit('render'); - }); + } }; $scope.set_refresh = function(state) { @@ -251,7 +261,7 @@ define([ } else if (scope.panel.alignment === 'vertical(-90)') { return -90; - } + } else { return randomRotate(Math.random()); } diff --git a/src/app/panels/tagcloud/stopWords.js b/src/app/panels/tagcloud/stopWords.js index e4a9e2422..fc48cf26f 100644 --- a/src/app/panels/tagcloud/stopWords.js +++ b/src/app/panels/tagcloud/stopWords.js @@ -1,3 +1 @@ -/* jshint ignore:start */ var stopwords = ["by", "owing", "anything", "theirs", "of", "here", "they're", "theres", "hed", "contain", "howbeit", "more", "once", "appropriate", "how", "hereby", "above", "isn't", "they", "nothing", "keep", "old", "i'll", "pp", "present", "unlikely", "give", "tends", "truly", "let", "sure", "cant", "you'd", "very", "im", "why", "therefore", "if", "other", "announce", "few", "be", "you've", "herself", "overall", "h", "affecting", "ltd", "ones", "see", "out", "briefly", "these", "largely", "are", "according", "she'll", "k", "really", "ninety", "made", "que", "until", "quite", "unless", "fix", "per", "gotten", "whereby", "lately", "i'm", "should", "might", "potentially", "may", "mrs", "sufficiently", "better", "definitely", "results", "nevertheless", "up", "going", "useful", "recent", "he'll", "ed", "ignored", "ourselves", "perhaps", "always", "immediately", "least", "substantially", "home", "course", "couldn't", "use", "slightly", "to", "towards", "beginnings", "was", "became", "hid", "others", "various", "him", "thanks", "us", "after", "co", "and", "all", "only", "then", "merely", "wish", "seriously", "eighty", "too", "your", "affects", "specifically", "thanx", "hasn't", "refs", "there", "further", "she'd", "as", "ok", "ord", "eight", "pages", "that", "know", "previously", "an", "a's", "inner", "ought", "nonetheless", "everywhere", "want", "accordance", "need", "during", "went", "themselves", "obviously", "et-al", "greetings", "certainly", "five", "million", "past", "hes", "significant", "arise", "most", "whom", "than", "being", "former", "were", "could", "arent", "apparently", "considering", "whenever", "sub", "come", "id", "tell", "it'll", "near", "selves", "twice", "omitted", "anyways", "there's", "anyway", "also", "whereas", "anyhow", "consider", "done", "available", "cause", "wherein", "wasn't", "itd", "seeing", "nearly", "showed", "due", "thoroughly", "that's", "let's", "taken", "related", "within", "o", "indicated", "am", "seen", "primarily", "whereupon", "at", "almost", "presumably", "we're", "seem", "wants", "didn't", "despite", "where", "neither", "thereupon", "upon", "resulting", "maybe", "plus", "over", "able", "everything", "later", "last", "specify", "biol", "them", "for", "having", "toward", "regardless", "followed", "asking", "via", "who", "following", "onto", "concerning", "afterwards", "i'd", "on", "novel", "shall", "where's", "below", "means", "sorry", "appear", "nd", "similar", "name", "necessarily", "now", "respectively", "even", "ca", "it's", "known", "etc", "mean", "somehow", "t's", "well", "becoming", "along", "although", "you're", "ending", "act", "found", "line", "aside", "else", "whither", "willing", "yourself", "currently", "un", "insofar", "indicate", "her", "under", "heres", "seemed", "another", "page", "both", "s", "latter", "never", "thank", "but", "immediate", "okay", "uses", "such", "sometime", "th", "behind", "shes", "non", "been", "three", "proud", "about", "added", "yes", "cannot", "yours", "wouldn't", "thorough", "gets", "soon", "suggest", "edu", "goes", "mg", "throughout", "whence", "everybody", "into", "in", "meanwhile", "shows", "m", "specified", "no", "adj", "trying", "each", "noted", "second", "between", "she", "mustn't", "moreover", "showns", "far", "would", "ever", "tried", "somebody", "his", "certain", "using", "instead", "across", "lest", "described", "take", "'ll", "our", "first", "or", "yourselves", "saw", "third", "must", "looking", "ours", "e", "mug", "whatever", "already", "much", "specifying", "thus", "somewhere", "b", "hereupon", "six", "giving", "because", "just", "kg", "re", "several", "saying", "four", "whoever", "formerly", "example", "one", "i", "won't", "away", "contains", "invention", "right", "best", "causes", "those", "together", "rd", "significantly", "somewhat", "looks", "ref", "j", "have", "affected", "alone", "sometimes", "little", "say", "it'd", "provides", "itself", "thence", "do", "sent", "section", "though", "either", "becomes", "quickly", "exactly", "you'll", "said", "actually", "nos", "ie", "containing", "therein", "indicates", "wonder", "besides", "www", "every", "happens", "necessary", "you", "myself", "own", "end", "thru", "none", "possibly", "whole", "thereby", "resulted", "through", "placed", "inasmuch", "says", "from", "meantime", "show", "ff", "my", "successfully", "beside", "rather", "unfortunately", "eg", "hereafter", "ran", "their", "particular", "think", "shed", "however", "sec", "brief", "c's", "needs", "et", "sup", "himself", "usually", "viz", "someone", "why's", "unto", "hither", "hello", "doesn't", "keeps", "keep keeps", "herein", "different", "hopefully", "is", "seven", "nay", "look", "anywhere", "while", "so", "c'mon", "possible", "information", "with", "allow", "back", "seeming", "outside", "n", "normally", "lets", "it", "they'll", "p", "given", "g", "we'd", "when's", "believe", "beforehand", "can", "go", "nowhere", "off", "liked", "many", "similarly", "thereafter", "particularly", "vs", "relatively", "had", "accordingly", "what's", "still", "somethan", "oh", "what", "stop", "probably", "inc", "downwards", "na", "has", "help", "especially", "make", "put", "latterly", "mostly", "appreciate", "elsewhere", "its", "does", "apart", "which", "noone", "nor", "indeed", "like", "strongly", "they'd", "we've", "namely", "regards", "not", "begins", "poorly", "they've", "forth", "way", "something", "gone", "will", "ain't", "shown", "before", "ah", "ml", "less", "whether", "importance", "me", "furthermore", "com", "this", "makes", "self", "aren't", "getting", "l", "when", "how's", "gives", "who's", "allows", "knows", "again", "value", "reasonably", "ex", "i've", "whose", "c", "tries", "date", "haven't", "except", "can't", "welcome", "likely", "become", "we'll", "corresponding", "changes", "auth", "wherever", "seems", "mr", "did", "r", "secondly", "he'd", "begin", "she's", "new", "readily", "fifth", "otherwise", "don't", "around", "nine", "sensible", "predominantly", "used", "hers", "part", "against", "a", "inward", "qv", "doing", "obtain", "follows", "kept", "obtained", "yet", "effect", "got", "approximately", "km", "without", "next", "came", "hadn't", "consequently", "get", "entirely", "beginning", "q", "same", "serious", "miss", "associated", "shouldn't", "anyone", "run", "abst", "clearly", "thats", "we", "aren", "often", "shan't", "here's", "mainly", "some", "index", "d", "the", "please", "research", "recently", "among", "couldnt", "enough", "hi", "ask", "he's", "beyond", "nobody", "took", "whereafter", "hardly", "comes", "try", "gave", "hence", "hundred", "down", "any", "since", "amongst", "anybody", "everyone", "awfully", "anymore", "zero", "two", "weren't", "he", "regarding", "important", "promptly", "f"]; -/* jshint ignore:end */ diff --git a/src/app/panels/template/editor.html b/src/app/panels/template/editor.html index 46975df71..ca5ab23b0 100644 --- a/src/app/panels/template/editor.html +++ b/src/app/panels/template/editor.html @@ -7,4 +7,11 @@
-
\ No newline at end of file +
+
+
Linkage Effective
+
+ +
+ +
diff --git a/src/app/panels/template/module.html b/src/app/panels/template/module.html index 41cbb3c6d..400e35603 100644 --- a/src/app/panels/template/module.html +++ b/src/app/panels/template/module.html @@ -9,5 +9,7 @@ text-anchor: end; } - +
+ +
\ No newline at end of file diff --git a/src/app/panels/template/module.js b/src/app/panels/template/module.js index 1e84f8170..d13beadc1 100644 --- a/src/app/panels/template/module.js +++ b/src/app/panels/template/module.js @@ -17,14 +17,7 @@ function (angular, app, _, $, d3) { module.controller('bar', function($scope, dashboard, querySrv, filterSrv) { $scope.panelMeta = { - modals: [ - { - description: 'Inspect', - icon: 'icon-info-sign', - partial: 'app/partials/inspector.html', - show: $scope.panel.spyable - } - ], + editorTabs: [ { title: 'Queries', @@ -43,8 +36,11 @@ function (angular, app, _, $, d3) { custom: '' }, field: '', + linkage_id:'a', max_rows: 10, spyable: true, + display:'block', + icon:"icon-caret-down", show_queries: true }; @@ -73,51 +69,64 @@ function (angular, app, _, $, d3) { $scope.render = function() { $scope.$emit('render'); }; + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; $scope.get_data = function() { - // Show the spinning wheel icon - $scope.panelMeta.loading = true; + if(($scope.panel.linkage_id === dashboard.current.linkage_id)||dashboard.current.enable_linkage){ - // Set Solr server - $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); - var request = $scope.sjs.Request(); + // Show the spinning wheel icon + $scope.panelMeta.loading = true; - // Construct Solr query - var fq = ''; - if (filterSrv.getSolrFq()) { - fq = '&' + filterSrv.getSolrFq(); - } - var wt = '&wt=csv'; - var fl = '&fl=' + $scope.panel.field; - var rows_limit = '&rows=' + $scope.panel.max_rows; + // Set Solr server + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + var request = $scope.sjs.Request(); - $scope.panel.queries.query = querySrv.getQuery(0) + fq + fl + wt + rows_limit; + // Construct Solr query + var fq = ''; + if (filterSrv.getSolrFq()) { + fq = '&' + filterSrv.getSolrFq(); + } + var wt = '&wt=csv'; + var fl = '&fl=' + $scope.panel.field; + var rows_limit = '&rows=' + $scope.panel.max_rows; - // Set the additional custom query - if ($scope.panel.queries.custom != null) { - request = request.setQuery($scope.panel.queries.query + $scope.panel.queries.custom); - } else { - request = request.setQuery($scope.panel.queries.query); - } + $scope.panel.queries.query = querySrv.getQuery(0) + fq + fl + wt + rows_limit; - // Execute the search and get results - var results = request.doSearch(); + // Set the additional custom query + if ($scope.panel.queries.custom != null) { + request = request.setQuery($scope.panel.queries.query + $scope.panel.queries.custom); + } else { + request = request.setQuery($scope.panel.queries.query); + } - // Populate scope when we have results - results.then(function(results) { - $scope.data = {}; + // Execute the search and get results + var results = request.doSearch(); - var parsedResults = d3.csv.parse(results, function(d) { - d[$scope.panel.field] = +d[$scope.panel.field]; // coerce to number - return d; - }); + // Populate scope when we have results + results.then(function (results) { + $scope.data = {}; - $scope.data = _.pluck(parsedResults,$scope.panel.field); - $scope.render(); - }); + var parsedResults = d3.csv.parse(results, function (d) { + d[$scope.panel.field] = +d[$scope.panel.field]; // coerce to number + return d; + }); + + $scope.data = _.pluck(parsedResults, $scope.panel.field); + $scope.render(); + }); - // Hide the spinning wheel icon - $scope.panelMeta.loading = false; + // Hide the spinning wheel icon + $scope.panelMeta.loading = false; + } }; }); diff --git a/src/app/panels/terms/editor.html b/src/app/panels/terms/editor.html old mode 100755 new mode 100644 index 400353086..003ef4893 --- a/src/app/panels/terms/editor.html +++ b/src/app/panels/terms/editor.html @@ -21,7 +21,16 @@ ng-options="f for f in ['descending','ascending']" ng-change="set_refresh(true)"> +
+ + +
+
+ + +
+
@@ -34,17 +43,17 @@
- +
-
+
-
+
-
+
@@ -54,16 +63,16 @@
-
+
-
+
-
+
-
+
@@ -72,7 +81,7 @@
-
+
@@ -96,4 +105,11 @@
Real-time (Auto-refresh)
-
\ No newline at end of file +
+
+
Linkage Effective
+
+ +
+ +
diff --git a/src/app/panels/terms/module.html b/src/app/panels/terms/module.html old mode 100755 new mode 100644 index 7d81f72c1..6d40ae514 --- a/src/app/panels/terms/module.html +++ b/src/app/panels/terms/module.html @@ -38,11 +38,32 @@ overflow:overlay; padding-right:10px } - + + .label{ + font-size:22.5px; + fill:#ffffff; + text-anchor:middle; + alignment-baseline:middle; + } + .face{ + stroke:#c8c8c8; + stroke-width:2; + } + .minorTicks{ + stroke-width:2; + stroke:white; + } + .majorTicks{ + stroke:white; + stroke-width:3; + } + + +
-
+
- +
@@ -50,16 +71,18 @@
{{term.label}} {{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}
-
+
{{term.label}} ({{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}})

- - +
{{data.length - 2}}
+ + +
-
+
@@ -69,11 +92,11 @@
-
+
-
+
- +
@@ -81,7 +104,7 @@
{{term.label}} {{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}}
-
+
{{term.label}} ({{dashboard.numberWithCommas(term.data[0][1].toFixed(panel.decimal_points))}})

@@ -89,14 +112,14 @@ - +
- - + + +
Term {{panel.mode | capitalize}} Action
{{term.label}} {{term.data[0][1].toFixed(panel.decimal_points)}} @@ -111,4 +134,5 @@
- \ No newline at end of file + + diff --git a/src/app/panels/terms/module.js b/src/app/panels/terms/module.js old mode 100755 new mode 100644 index 8dcb2890e..f25c30aca --- a/src/app/panels/terms/module.js +++ b/src/app/panels/terms/module.js @@ -15,8 +15,11 @@ define([ 'app', 'underscore', 'jquery', - 'kbn' -], + 'kbn', + 'echarts', + 'd3', + 'viz', + ], function (angular, app, _, $, kbn) { 'use strict'; @@ -25,14 +28,7 @@ function (angular, app, _, $, kbn) { module.controller('terms', function($scope, $timeout, timer, querySrv, dashboard, filterSrv) { $scope.panelMeta = { - modals : [ - { - description: "Inspect", - icon: "icon-info-sign", - partial: "app/partials/inspector.html", - show: $scope.panel.spyable - } - ], + exportfile: true, editorTabs : [ {title:'Queries', src:'app/partials/querySelect.html'} @@ -56,10 +52,16 @@ function (angular, app, _, $, kbn) { exclude : [], missing : false, other : false, - size : 10, + size : 10000, + display:'block', + icon:"icon-caret-down", sortBy : 'count', + threshold_first:3000, + threshold_second:5000, order : 'descending', style : { "font-size": '10pt'}, + fontsize:20, + linkage_id:'a', donut : false, tilt : false, labels : true, @@ -107,7 +109,17 @@ function (angular, app, _, $, kbn) { return; } }; + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; /** * * @@ -189,144 +201,168 @@ function (angular, app, _, $, kbn) { }; $scope.get_data = function() { - // Make sure we have everything for the request to complete - if(dashboard.indices.length === 0) { - return; - } + if(($scope.panel.linkage_id === dashboard.current.linkage_id)||dashboard.current.enable_linkage){ + // Make sure we have everything for the request to complete + if (dashboard.indices.length === 0) { + return; + } - delete $scope.panel.error; - $scope.panelMeta.loading = true; - var request, results; + delete $scope.panel.error; + $scope.panelMeta.loading = true; + var request, results; - $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); + $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); - request = $scope.sjs.Request().indices(dashboard.indices); - $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); + request = $scope.sjs.Request().indices(dashboard.indices); + $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); - // Populate the inspector panel - $scope.inspector = angular.toJson(JSON.parse(request.toString()),true); + // Populate the inspector panel + $scope.inspector = angular.toJson(JSON.parse(request.toString()), true); - var query = this.build_query('json', false); + var query = this.build_query('json', false); - // Set the panel's query - $scope.panel.queries.query = query; + // Set the panel's query + $scope.panel.queries.query = query; - request.setQuery(query); + request.setQuery(query); - results = request.doSearch(); + results = request.doSearch(); - // Populate scope when we have results - results.then(function(results) { - // Check for error and abort if found - if(!(_.isUndefined(results.error))) { - $scope.panel.error = $scope.parse_error(results.error.msg); - $scope.data = []; - $scope.panelMeta.loading = false; - $scope.$emit('render'); - return; - } + // Populate scope when we have results + results.then(function (results) { + // Check for error and abort if found + if (!(_.isUndefined(results.error))) { + $scope.panel.error = $scope.parse_error(results.error.msg); + $scope.data = []; + $scope.panelMeta.loading = false; + $scope.$emit('render'); + return; + } - // Function for validating HTML color by assign it to a dummy
- // and let the browser do the work of validation. - var isValidHTMLColor = function(color) { - // clear attr first, before comparison - $('#colorTest').removeAttr('style'); - var valid = $('#colorTest').css('color'); - $('#colorTest').css('color', color); + // Function for validating HTML color by assign it to a dummy
+ // and let the browser do the work of validation. + var isValidHTMLColor = function (color) { + // clear attr first, before comparison + $('#colorTest').removeAttr('style'); + var valid = $('#colorTest').css('color'); + $('#colorTest').css('color', color); + + if (valid === $('#colorTest').css('color')) { + return false; + } else { + return true; + } + }; - if (valid === $('#colorTest').css('color')) { - return false; - } else { - return true; - } - }; + // Function for customizing chart color by using field values as colors. + var addSliceColor = function (slice, color) { + if ($scope.panel.useColorFromField && isValidHTMLColor(color)) { + slice.color = color; + } + return slice; + }; + + var sum = 0; + var k = 0; + var missing = 0; + $scope.panelMeta.loading = false; + $scope.hits = results.response.numFound; + $scope.data = []; + + if ($scope.panel.mode === 'count') { + // In count mode, the y-axis min should be zero because count value cannot be negative. + $scope.yaxis_min = 0; + _.each(results.facet_counts.facet_fields, function (v) { + for (var i = 0; i < v.length; i++) { + var term = v[i]; + i++; + var count = v[i]; + sum += count; + if (term === null) { + missing = count; + } else { + // if count = 0, do not add it to the chart, just skip it + if (count === 0) { + continue; + } + var slice = {label: term, data: [[k, count]], actions: true}; + slice = addSliceColor(slice, term); + $scope.data.push(slice); + } + } + }); + } else { + // In stats mode, set y-axis min to null so jquery.flot will set the scale automatically. + $scope.yaxis_min = null; + _.each(results.stats.stats_fields[$scope.panel.stats_field].facets[$scope.panel.field], function (stats_obj, facet_field) { + var slice = {label: facet_field, data: [[k, stats_obj[$scope.panel.mode]]], actions: true}; + $scope.data.push(slice); + }); + } + // Sort the results + $scope.data = _.sortBy($scope.data, function (d) { + return $scope.panel.sortBy === 'index' ? d.label : d.data[0][1]; + }); + if ($scope.panel.order === 'descending') { + $scope.data.reverse(); + } - // Function for customizing chart color by using field values as colors. - var addSliceColor = function(slice,color) { - if ($scope.panel.useColorFromField && isValidHTMLColor(color)) { - slice.color = color; - } - return slice; - }; - - var sum = 0; - var k = 0; - var missing =0; - $scope.panelMeta.loading = false; - $scope.hits = results.response.numFound; - $scope.data = []; - - if ($scope.panel.mode === 'count') { - // In count mode, the y-axis min should be zero because count value cannot be negative. - $scope.yaxis_min = 0; - _.each(results.facet_counts.facet_fields, function(v) { - for (var i = 0; i < v.length; i++) { - var term = v[i]; - i++; - var count = v[i]; - sum += count; - if(term === null){ - missing = count; - }else{ - // if count = 0, do not add it to the chart, just skip it - if (count === 0) { continue; } - var slice = { label : term, data : [[k,count]], actions: true}; - slice = addSliceColor(slice,term); - $scope.data.push(slice); - } + // Slice it according to panel.size, and then set the x-axis values with k. + $scope.data = $scope.data.slice(0, $scope.panel.size); + _.each($scope.data, function (v) { + v.data[0][0] = k; + k++; + }); + + if ($scope.panel.field && $scope.fields.typeList[$scope.panel.field] && $scope.fields.typeList[$scope.panel.field].schema.indexOf("T") > -1) { + $scope.hits = sum; } - }); - } else { - // In stats mode, set y-axis min to null so jquery.flot will set the scale automatically. - $scope.yaxis_min = null; - _.each(results.stats.stats_fields[$scope.panel.stats_field].facets[$scope.panel.field], function(stats_obj,facet_field) { - var slice = { label:facet_field, data:[[k,stats_obj[$scope.panel.mode]]], actions: true }; - $scope.data.push(slice); - }); - } - // Sort the results - $scope.data = _.sortBy($scope.data, function(d) { - return $scope.panel.sortBy === 'index' ? d.label : d.data[0][1]; - }); - if ($scope.panel.order === 'descending') { - $scope.data.reverse(); - } - // Slice it according to panel.size, and then set the x-axis values with k. - $scope.data = $scope.data.slice(0,$scope.panel.size); - _.each($scope.data, function(v) { - v.data[0][0] = k; - k++; + $scope.data.push({ + label: 'Missing field', + // data:[[k,results.facets.terms.missing]],meta:"missing",color:'#aaa',opacity:0}); + // TODO: Hard coded to 0 for now. Solr faceting does not provide 'missing' value. + data: [[k, missing]], meta: "missing", color: '#aaa', opacity: 0 + }); + $scope.data.push({ + label: 'Other values', + // data:[[k+1,results.facets.terms.other]],meta:"other",color:'#444'}); + // TODO: Hard coded to 0 for now. Solr faceting does not provide 'other' value. + data: [[k + 1, $scope.hits - sum]], meta: "other", color: '#444' + }); + + $scope.$emit('render'); }); + } + }; - if ($scope.panel.field && $scope.fields.typeList[$scope.panel.field] && $scope.fields.typeList[$scope.panel.field].schema.indexOf("T") > -1) { - $scope.hits = sum; - } + $scope.build_search = function(term,negate) { - $scope.data.push({label:'Missing field', - // data:[[k,results.facets.terms.missing]],meta:"missing",color:'#aaa',opacity:0}); - // TODO: Hard coded to 0 for now. Solr faceting does not provide 'missing' value. - data:[[k,missing]],meta:"missing",color:'#aaa',opacity:0}); - $scope.data.push({label:'Other values', - // data:[[k+1,results.facets.terms.other]],meta:"other",color:'#444'}); - // TODO: Hard coded to 0 for now. Solr faceting does not provide 'other' value. - data:[[k+1,$scope.hits-sum]],meta:"other",color:'#444'}); + if (_.isUndefined(term.meta)) { + if ($scope.panel.chart === 'ebar') { + filterSrv.set({ + type: 'terms', field: $scope.panel.field, value: term.name, + mandate: (negate ? 'mustNot' : 'must') + }); + } else { + filterSrv.set({ + type: 'terms', field: $scope.panel.field, value: term.label, + mandate: (negate ? 'mustNot' : 'must') + }); + } + } else if (term.meta === 'missing') { + filterSrv.set({ + type: 'exists', field: $scope.panel.field, + mandate: (negate ? 'must' : 'mustNot') + }); + } else { + return; + } + dashboard.current.linkage_id = $scope.panel.linkage_id; + dashboard.current.enable_linkage = false; + dashboard.refresh(); - $scope.$emit('render'); - }); - }; - $scope.build_search = function(term,negate) { - if(_.isUndefined(term.meta)) { - filterSrv.set({type:'terms',field:$scope.panel.field,value:term.label, - mandate:(negate ? 'mustNot':'must')}); - } else if(term.meta === 'missing') { - filterSrv.set({type:'exists',field:$scope.panel.field, - mandate:(negate ? 'must':'mustNot')}); - } else { - return; - } - dashboard.refresh(); }; $scope.set_refresh = function (state) { @@ -370,7 +406,7 @@ function (angular, app, _, $, kbn) { return { restrict: 'A', link: function(scope, elem) { - + var myChart; // Receive render events scope.$on('render',function(){ render_panel(); @@ -383,6 +419,9 @@ function (angular, app, _, $, kbn) { // Function for rendering panel function render_panel() { + + elem.html(""); + var plot, chartData; var colors = []; @@ -390,6 +429,7 @@ function (angular, app, _, $, kbn) { elem.css({height:scope.panel.height||scope.row.height}); // Make a clone we can operate on. + chartData = _.clone(scope.data); chartData = scope.panel.missing ? chartData : _.without(chartData,_.findWhere(chartData,{meta:'missing'})); @@ -401,107 +441,531 @@ function (angular, app, _, $, kbn) { } else { colors = scope.panel.chartColors; } - + + var AP_1 = 0.0; + var AP_2 = 0.0; + var AP_n = 0.0; + for (var i = 0; i < chartData.length; i++) { + AP_n = AP_n+chartData[i].data[0][1]; + if(parseInt(chartData[i].label)<=scope.panel.threshold_first ){ + AP_1+=chartData[i].data[0][1]; + }else if(parseInt(chartData[i].label)scope.panel.threshold_first){ + AP_2+=chartData[i].data[0][1]*0.5; + } + } + var APdex =100; + if(AP_n !== 0){ + APdex = parseInt(100*(AP_1+AP_2)/AP_n); + } + + var option_nodata = { + series: [{ + + type: 'wordCloud', + //size: ['9%', '99%'], + sizeRange: [50, 50], + //textRotation: [0, 45, 90, -45], + rotationRange: [0, 0], + //shape: 'circle', + textPadding: 0, + autoSize: { + enable: true, + minSize: 6 + }, + textStyle: { + normal: { + color: '#1a93f9' + }, + emphasis: { + shadowBlur: 10, + shadowColor: '#333' + } + }, + data: [{ + name: "NO DATA", + value: 1 + }] + }] +}; + + var idd = scope.$id; + var echarts = require('echarts'); + if(myChart) { + myChart.dispose(); + } require(['jquery.flot.pie'], function(){ - // Populate element - try { - // Add plot to scope so we can build out own legend - if(scope.panel.chart === 'bar') { - var yAxisConfig = { - show: true, - min: scope.yaxis_min, - color: "#c8c8c8" - }; - if (scope.panel.logAxis) { - _.defaults(yAxisConfig, { - ticks: function (axis) { - var res = [], v, i = 1, - ticksNumber = 8, - max = axis.max === 0 ? 0 : Math.log(axis.max), - min = axis.min === 0 ? 0 : Math.log(axis.min), - interval = (max - min) / ticksNumber; - do { - v = interval * i; - res.push(Math.exp(v)); - ++i; - } while (v < max); - return res; - }, - transform: function (v) { - return v === 0 ? 0 : Math.log(v); }, - inverseTransform: function (v) { - return v === 0 ? 0 : Math.exp(v); } - }); - } + var labelcolor = false; + if (dashboard.current.style === 'dark'){ + labelcolor = true; + } + // Add plot to scope so we can build out own legend + if(scope.panel.chart === 'dashboard') { + + myChart = echarts.init(document.getElementById(idd)); + + var option = { + - plot = $.plot(elem, chartData, { - legend: { show: false }, - series: { - lines: { show: false }, - bars: { show: true, fill: 1, barWidth: 0.8, horizontal: false }, - shadowSize: 1 + toolbox: { + show : false, + feature : { + mark : {show: false}, + restore : {show: false}, + saveAsImage : {show: false} + } + }, + grid: { + left: '0%', + right: '0%', + bottom: '0%', + top: 90 + }, + series : [ + { + name:'Health', + + type:'gauge', + min:100, + max:0, + splitNumber:10, + radius: '96%', + axisLine: { // åæ ‡è½´çº¿ + lineStyle: { // 属性lineStyleæŽ§åˆ¶çº¿æ¡æ ·å¼ + color: [[0.6, '#1e90ff'],[0.82, '#F6AB60'],[1, '#EB5768']], + width: 5, + shadowColor : '#ddfdfa', //é»˜è®¤é€æ˜Ž + shadowBlur: 40 + } }, - // yaxis: { show: true, min: 0, color: "#c8c8c8" }, - yaxis: yAxisConfig, - xaxis: { show: false }, - grid: { - borderWidth: 0, - borderColor: '#eee', - color: "#eee", - hoverable: true, - clickable: true + axisLabel: { // åæ ‡è½´å°æ ‡è®° + textStyle: { // 属性lineStyleæŽ§åˆ¶çº¿æ¡æ ·å¼ + fontWeight: 'bolder', + color: labelcolor?'#fff':'#696969', + shadowColor : '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 40, + fontStyle: 'italic', + fontSize:scope.panel.fontsize + } }, - colors: colors - }); + axisTick: { // åæ ‡è½´å°æ ‡è®° + length :18, // 属性length控制线长 + lineStyle: { // 属性lineStyleæŽ§åˆ¶çº¿æ¡æ ·å¼ + color: 'auto', + shadowColor : '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 40 + } + }, + splitLine: { // 分隔线 + length :28, // 属性length控制线长 + lineStyle: { // 属性lineStyle(详è§lineStyleï¼‰æŽ§åˆ¶çº¿æ¡æ ·å¼ + width:4, + color: '#fff', + shadowColor : '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 40 + } + }, + pointer: { // 分隔线 + length:'90%', + width:3 + }, + itemStyle:{ + normal:{ + color:'#fff', + shadowColor: '#f55351', + shadowBlur: 30, + borderWidth:2, + borderColor: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, color: 'red' // 0% 处的颜色 + }, { + offset: 0.7, color: '#f8750d' // 100% 处的颜色 + },{ + offset: 1, color: '#fff' // 100% 处的颜色 + }], false) + }, + emphasis:{ + color:'#fff', + shadowColor: '#fff', + shadowBlur: 30, + borderWidth:2, + borderColor: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, color: 'red' // 0% 处的颜色 + }, { + offset: 0.7, color: '#50d1f1' // 100% 处的颜色 + },{ + offset: 1, color: '#fff' // 100% 处的颜色 + }], false) + + } + }, + title : { + textStyle: { // 其余属性默认使用全局文本样å¼ï¼Œè¯¦è§TEXTSTYLE + fontWeight: 'bolder', + fontSize: scope.panel.fontsize+20, + fontStyle: 'italic', + color: labelcolor?'#fff':'#696969', + shadowColor : '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 40 + } + }, + detail : { + formatter:'{value}%', + // x, y,å•ä½px + textStyle: { // 其余属性默认使用全局文本样å¼ï¼Œè¯¦è§TEXTSTYLE + fontWeight: 'bolder', + color: labelcolor?'#fff':'#696969', + fontSize:scope.panel.fontsize+10 + } + }, + data:[{value: APdex, name: 'Health State'}] } - if(scope.panel.chart === 'pie') { - var labelFormat = function(label, series){ - return '
'+ - label+'
'+Math.round(series.percent)+'%
'; - }; - // DEfulat style for labels that is implmented in jquery flot - // var position = ""; - // if (scope.panel.counter_pos == "left") - // position = "nw"; - // else if (scope.panel.counter_pos == "right") - // position = "ne"; - - plot = $.plot(elem, chartData, { - legend: { - show: false - // position: position, - // backgroundColor: "transparent" + ] + }; + var option_health_nodata = { + + + toolbox: { + show : false, + feature : { + mark : {show: false}, + restore : {show: false}, + saveAsImage : {show: false} + } + }, + grid: { + left: '0%', + right: '0%', + bottom: '0%', + top: 90 + }, + series : [ + { + name:'Health', + + type:'gauge', + min:100, + max:0, + splitNumber:10, + radius: '96%', + axisLine: { // åæ ‡è½´çº¿ + lineStyle: { // 属性lineStyleæŽ§åˆ¶çº¿æ¡æ ·å¼ + color: [[0.6, '#1e90ff'],[0.82, '#F6AB60'],[1, '#EB5768']], + width: 5, + shadowColor : '#ddfdfa', //é»˜è®¤é€æ˜Ž + shadowBlur: 40 + } }, - series: { - pie: { - innerRadius: scope.panel.donut ? 0.4 : 0, - tilt: scope.panel.tilt ? 0.45 : 1, - radius: 1, - show: true, - combine: { - color: '#999', - label: 'The Rest' - }, - stroke: { - width: 0 - }, - label: { - show: scope.panel.labels, - radius: 2/3, - formatter: labelFormat, - threshold: 0.1 + axisLabel: { // åæ ‡è½´å°æ ‡è®° + textStyle: { // 属性lineStyleæŽ§åˆ¶çº¿æ¡æ ·å¼ + fontWeight: 'bolder', + color: labelcolor?'#fff':'#696969', + shadowColor : '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 40, + fontStyle: 'italic', + fontSize:scope.panel.fontsize } - } }, - //grid: { hoverable: true, clickable: true }, - grid: { hoverable: true, clickable: true }, - colors: colors - }); + axisTick: { // åæ ‡è½´å°æ ‡è®° + length :18, // 属性length控制线长 + lineStyle: { // 属性lineStyleæŽ§åˆ¶çº¿æ¡æ ·å¼ + color: 'auto', + shadowColor : '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 40 + } + }, + splitLine: { // 分隔线 + length :28, // 属性length控制线长 + lineStyle: { // 属性lineStyle(详è§lineStyleï¼‰æŽ§åˆ¶çº¿æ¡æ ·å¼ + width:4, + color: '#fff', + shadowColor : '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 40 + } + }, + pointer: { // 分隔线 + length:'90%', + width:3 + }, + itemStyle:{ + normal:{ + color:'#fff', + shadowColor: '#f55351', + shadowBlur: 30, + borderWidth:2, + borderColor: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, color: 'red' // 0% 处的颜色 + }, { + offset: 0.7, color: '#f8750d' // 100% 处的颜色 + },{ + offset: 1, color: '#fff' // 100% 处的颜色 + }], false) + }, + emphasis:{ + color:'#fff', + shadowColor: '#fff', + shadowBlur: 30, + borderWidth:2, + borderColor: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, color: 'red' // 0% 处的颜色 + }, { + offset: 0.7, color: '#50d1f1' // 100% 处的颜色 + },{ + offset: 1, color: '#fff' // 100% 处的颜色 + }], false) + + } + }, + title : { + textStyle: { // 其余属性默认使用全局文本样å¼ï¼Œè¯¦è§TEXTSTYLE + fontWeight: 'bolder', + fontSize: scope.panel.fontsize+15, + fontStyle: 'italic', + color: labelcolor?'#fff':'#696969', + shadowColor : '#fff', //é»˜è®¤é€æ˜Ž + shadowBlur: 40 + } + }, + detail : { + formatter:'{value}%', + // x, y,å•ä½px + textStyle: { // 其余属性默认使用全局文本样å¼ï¼Œè¯¦è§TEXTSTYLE + fontWeight: 'bolder', + color: labelcolor?'#fff':'#696969', + fontSize:scope.panel.fontsize+10 + } + }, + data:[{value: 0, name: 'Health State(no data)'}] + } + + ] + }; + + if(chartData.length === 0){ + myChart.setOption(option_health_nodata);}else{ + myChart.setOption(option); + } + // 使用刚指定的é…ç½®é¡¹å’Œæ•°æ®æ˜¾ç¤ºå›¾è¡¨ã€‚ + } + + if(scope.panel.chart === 'ebar') { + var arrdata = []; + var arrlabel = []; + var top4 = 5; + if(top4>chartData.length){ + top4 = chartData.length; + } + for (var i = 0; i < top4; i++) { + arrlabel[i] = chartData[i].label; + arrdata[i] = chartData[i].data[0][1]; + } + + myChart = echarts.init(document.getElementById(idd)); + var option1 = { + color: ['#3398DB'], + tooltip : { + trigger: 'axis', + axisPointer : { // åæ ‡è½´æŒ‡ç¤ºå™¨ï¼Œåæ ‡è½´è§¦å‘æœ‰æ•ˆ + type : 'shadow' // 默认为直线,å¯é€‰ä¸ºï¼š'line' | 'shadow' + } + }, + grid: { + left: '8%', + right: '3%', + bottom: '3%', + top: '6%', + containLabel: true + }, + xAxis : [ + { + type : 'category', + data : arrlabel, + axisLine:{ + show:false + }, + axisLabel:{ + show:false, + textStyle:{ + color:'#cde5fe', + fontSize:16, + + + } + + }, + axisTick: { + alignWithLabel: false } + } + ], + yAxis : [ + { + type : 'value', + splitLine: { + show :true, + lineStyle:{ + type:'dotted', + color: '#0d394a' + } + }, + axisLabel:{ + textStyle:{ + color:labelcolor?'#fff':'#696969', + fontSize:scope.panel.fontsize, + fontStyle: 'italic' + } + + }, + nameTextStyle:{ + + color:'#fff', + + }, + axisLine:{ + show:false + } + } + ], + series : [ + { + name:'Visit Top 5', + type:'bar', + barWidth: '43%', + data:arrdata, + itemStyle: { + normal: { + color: function(params) { + var colorList = ['#1a75f9', '#1a93f9', '#1ab0f9', '#1acef9', '#42d3f0', '#e59d87', '#759aa0', '#dc6b67', '#efdd79', '#8dc1aa', '#ea7d52', '#8dace7', '#a6a1e1', '#FECDA3', '#FED980']; + return colorList[params.dataIndex]; + }, + shadowColor: '#fff', + barBorderRadius: 5 + + }, + emphasis: { + color: function(params) { + var colorList = ['#ff951f', '#ff951f', '#ff951f', '#ff951f', '#ff951f', '#e59d87', '#759aa0', '#dc6b67', '#efdd79', '#8dc1aa', '#ea7d52', '#8dace7', '#a6a1e1', '#FECDA3', '#FED980']; + return colorList[params.dataIndex]; + }, + shadowColor: '#fff', + barBorderRadius: 5 + + } + } + } + ] + }; + // 使用刚指定的é…ç½®é¡¹å’Œæ•°æ®æ˜¾ç¤ºå›¾è¡¨ã€‚ + if(chartData.length === 0){ + myChart.setOption(option_nodata); + }else{ + myChart.setOption(option1); + myChart.on('click', function (params) { + // æŽ§åˆ¶å°æ‰“å°æ•°æ®çš„åç§° + scope.build_search(params); + }); + } + } + + if(scope.panel.chart === 'bar') { + var yAxisConfig = { + show: true, + min: scope.yaxis_min, + color: "#c8c8c8" + }; + if (scope.panel.logAxis) { + _.defaults(yAxisConfig, { + ticks: function (axis) { + var res = [], v, i = 1, + ticksNumber = 8, + max = axis.max === 0 ? 0 : Math.log(axis.max), + min = axis.min === 0 ? 0 : Math.log(axis.min), + interval = (max - min) / ticksNumber; + do { + v = interval * i; + res.push(Math.exp(v)); + ++i; + } while (v < max); + return res; + }, + transform: function (v) { + return v === 0 ? 0 : Math.log(v); }, + inverseTransform: function (v) { + return v === 0 ? 0 : Math.exp(v); } + }); + } + + plot = $.plot(elem, chartData, { + legend: { show: false }, + series: { + lines: { show: false }, + bars: { show: true, fill: 1, barWidth: 0.8, horizontal: false }, + shadowSize: 1 + }, + // yaxis: { show: true, min: 0, color: "#c8c8c8" }, + yaxis: yAxisConfig, + xaxis: { show: true }, + grid: { + borderWidth: 0, + borderColor: '#eee', + color: "#eee", + hoverable: true, + clickable: true + }, + colors: colors + }); + + if(chartData.length === 0){ + myChart = echarts.init(document.getElementById(idd)); + myChart.setOption(option_nodata); + + } + + } + + if(scope.panel.chart === 'pie') { + var labelFormat = function(label, series){ + return '
'+ + label+'
'+Math.round(series.percent)+'%
'; + }; + plot = $.plot(elem, chartData, { + legend: { + show: false + // position: position, + // backgroundColor: "transparent" + }, + series: { + pie: { + innerRadius: scope.panel.donut ? 0.4 : 0, + tilt: scope.panel.tilt ? 0.45 : 1, + radius: 1, + show: true, + combine: { + color: '#999', + label: 'The Rest' + }, + stroke: { + width: 0 + }, + label: { + show: scope.panel.labels, + radius: 2/3, + formatter: labelFormat, + threshold: 0.1 + } + } + }, + //grid: { hoverable: true, clickable: true }, + grid: { hoverable: true, clickable: true }, + colors: colors + }); + if(chartData.length === 0){ + myChart = echarts.init(document.getElementById(idd)); + myChart.setOption(option_nodata); + } + } // Populate legend if(elem.is(":visible")){ setTimeout(function(){ @@ -512,9 +976,6 @@ function (angular, app, _, $, kbn) { }); } - } catch(e) { - elem.text(e); - } }); } @@ -528,7 +989,7 @@ function (angular, app, _, $, kbn) { var $tooltip = $('
'); elem.bind("plothover", function (event, pos, item) { if (item) { - var value = scope.panel.chart === 'bar' ? item.datapoint[1] : item.datapoint[1][0][1]; + var value = scope.panel.chart === 'bar' ? item.datapoint[1] : item.datapoint[1][0][1]; // if (scope.panel.mode === 'count') { // value = value.toFixed(0); // } else { @@ -549,4 +1010,4 @@ function (angular, app, _, $, kbn) { }; }); -}); \ No newline at end of file +}); diff --git a/src/app/panels/text/editor.html b/src/app/panels/text/editor.html old mode 100755 new mode 100644 index 02177bc34..e68b35519 --- a/src/app/panels/text/editor.html +++ b/src/app/panels/text/editor.html @@ -3,14 +3,14 @@
-
+
-
\ No newline at end of file +
diff --git a/src/app/panels/text/lib/showdown.js b/src/app/panels/text/lib/showdown.js old mode 100755 new mode 100644 diff --git a/src/app/panels/text/module.html b/src/app/panels/text/module.html old mode 100755 new mode 100644 index 3b7269c09..797bea88e --- a/src/app/panels/text/module.html +++ b/src/app/panels/text/module.html @@ -1,10 +1,12 @@
- +
+ {{panel.content}} -

+

-

+

-
\ No newline at end of file +
+
diff --git a/src/app/panels/text/module.js b/src/app/panels/text/module.js old mode 100755 new mode 100644 index 2ee8b3c39..7fd21079b --- a/src/app/panels/text/module.js +++ b/src/app/panels/text/module.js @@ -27,6 +27,8 @@ function (angular, app, _, require) { var _d = { status : "Stable", mode : "markdown", + display:'block', + icon:"icon-caret-down", content : "", style: {}, }; @@ -35,6 +37,17 @@ function (angular, app, _, require) { $scope.init = function() { $scope.ready = false; }; + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; }); @@ -83,4 +96,4 @@ function (angular, app, _, require) { } }; }); -}); \ No newline at end of file +}); diff --git a/src/app/panels/timepicker/editor.html b/src/app/panels/timepicker/editor.html old mode 100755 new mode 100644 index 32daa1592..ce9e7f695 --- a/src/app/panels/timepicker/editor.html +++ b/src/app/panels/timepicker/editor.html @@ -26,10 +26,10 @@
Auto-refresh settings
- +
- +
\ No newline at end of file diff --git a/src/app/panels/timepicker/module.html b/src/app/panels/timepicker/module.html old mode 100755 new mode 100644 index 8b305cfde..ca57eb792 --- a/src/app/panels/timepicker/module.html +++ b/src/app/panels/timepicker/module.html @@ -4,8 +4,8 @@ display: inline-block; } -
- +
+
@@ -26,8 +26,6 @@
- -
@@ -41,38 +39,38 @@
- -
-
+
-
+

No time filter present

-
- diff --git a/src/app/panels/timepicker/module.js b/src/app/panels/timepicker/module.js index 5c682a37a..83785fc32 100644 --- a/src/app/panels/timepicker/module.js +++ b/src/app/panels/timepicker/module.js @@ -28,12 +28,7 @@ function (angular, app, _, moment, kbn, $) { module.controller('timepicker', function($scope, $rootScope, $timeout, timer, $http, dashboard, filterSrv) { $scope.panelMeta = { - modals: [{ - description: "Inspect", - icon: "icon-info-sign", - partial: "app/partials/inspector.html", - show: true - }], + status : "Stable", description : "A panel for controlling the time range filters. If you have time based data, "+ " or if you're using time stamped indices, you need one of these" @@ -48,6 +43,8 @@ function (angular, app, _, moment, kbn, $) { timefield: 'event_timestamp', timeformat: "", spyable: true, + display:'block', + icon:"icon-caret-down", refresh: { enable: false, interval: 30, @@ -88,7 +85,13 @@ function (angular, app, _, moment, kbn, $) { // These 3 statements basicly do everything time_apply() does set_timepicker($scope.time.from,$scope.time.to); update_panel(); - set_time_filter($scope.time); + + // If we're in a mode where something must be calculated, clear existing filters + // and set new ones + //if($scope.panel.mode !== 'absolute') { + set_time_filter($scope.time); + //} + dashboard.refresh(); // Start refresh timer if enabled @@ -110,8 +113,21 @@ function (angular, app, _, moment, kbn, $) { } } }); + dashboard.current.load = false; }; + $scope.display=function() { + if($scope.panel.display === 'none'){ + $scope.panel.display='block'; + $scope.panel.icon="icon-caret-down"; + + + }else{ + $scope.panel.display='none'; + $scope.panel.icon="icon-caret-up"; + } + }; + $scope.set_interval = function (refresh_interval) { $scope.panel.refresh.interval = refresh_interval; if(_.isNumber($scope.panel.refresh.interval)) { @@ -177,7 +193,6 @@ function (angular, app, _, moment, kbn, $) { }; $scope.time_apply(); }; - $scope.close_edit = function() { $scope.time_apply(); }; @@ -244,7 +259,7 @@ function (angular, app, _, moment, kbn, $) { update_panel(); set_time_filter($scope.time); - + dashboard.current.enable_linkage = true; dashboard.refresh(); }; diff --git a/src/app/panels/timepicker/refreshctrl.html b/src/app/panels/timepicker/refreshctrl.html old mode 100755 new mode 100644 index 51c91affc..b45d5a349 --- a/src/app/panels/timepicker/refreshctrl.html +++ b/src/app/panels/timepicker/refreshctrl.html @@ -1,5 +1,2 @@ -
-
- + -
\ No newline at end of file diff --git a/src/app/partials/alarm.html b/src/app/partials/alarm.html new file mode 100644 index 000000000..95044ea60 --- /dev/null +++ b/src/app/partials/alarm.html @@ -0,0 +1,81 @@ + + +
+ +
+ + + + +

Tab One

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla venenatis ante augue. Phasellus volutpat neque ac dui mattis vulputate. Etiam consequat aliquam cursus. In sodales pretium ultrices. Maecenas lectus est, sollicitudin consectetur felis nec, feugiat ultricies mi.

+
+
+ + +

Tab Two

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla venenatis ante augue. Phasellus volutpat neque ac dui mattis vulputate. Etiam consequat aliquam cursus. In sodales pretium ultrices. Maecenas lectus est, sollicitudin consectetur felis nec, feugiat ultricies mi. Aliquam erat volutpat. Nam placerat, tortor in ultrices porttitor, orci enim rutrum enim, vel tempor sapien arcu a tellus. Vivamus convallis sodales ante varius gravida. Curabitur a purus vel augue ultrices ultricies id a nisl. Nullam malesuada consequat diam, a facilisis tortor volutpat et. Sed urna dolor, aliquet vitae posuere vulputate, euismod ac lorem. Sed felis risus, pulvinar at interdum quis, vehicula sed odio. Phasellus in enim venenatis, iaculis tortor eu, bibendum ante. Donec ac tellus dictum neque volutpat blandit. Praesent efficitur faucibus risus, ac auctor purus porttitor vitae. Phasellus ornare dui nec orci posuere, nec luctus mauris semper.

+

Morbi viverra, ante vel aliquet tincidunt, leo dolor pharetra quam, at semper massa orci nec magna. Donec posuere nec sapien sed laoreet. Etiam cursus nunc in condimentum facilisis. Etiam in tempor tortor. Vivamus faucibus egestas enim, at convallis diam pulvinar vel. Cras ac orci eget nisi maximus cursus. Nunc urna libero, viverra sit amet nisl at, hendrerit tempor turpis. Maecenas facilisis convallis mi vel tempor. Nullam vitae nunc leo. Cras sed nisl consectetur, rhoncus sapien sit amet, tempus sapien.

+

Integer turpis erat, porttitor vitae mi faucibus, laoreet interdum tellus. Curabitur posuere molestie dictum. Morbi eget congue risus, quis rhoncus quam. Suspendisse vitae hendrerit erat, at posuere mi. Cras eu fermentum nunc. Sed id ante eu orci commodo volutpat non ac est. Praesent ligula diam, congue eu enim scelerisque, finibus commodo lectus.

+
+
+ + +

Tab Three

+

Integer turpis erat, porttitor vitae mi faucibus, laoreet interdum tellus. Curabitur posuere molestie dictum. Morbi eget congue risus, quis rhoncus quam. Suspendisse vitae hendrerit erat, at posuere mi. Cras eu fermentum nunc. Sed id ante eu orci commodo volutpat non ac est. Praesent ligula diam, congue eu enim scelerisque, finibus commodo lectus.

+
+
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
first namelast namebirth datebalanceemail
+ + + +
{{row.firstName | uppercase}}{{row.lastName}}{{row.birthDate | date}}{{row.balance | currency}}email
+ +
+
+
+ diff --git a/src/app/partials/dashLoader.html b/src/app/partials/dashLoader.html old mode 100755 new mode 100644 index bd9f0d98c..2bd7cc753 --- a/src/app/partials/dashLoader.html +++ b/src/app/partials/dashLoader.html @@ -1,157 +1,91 @@ - - - -
  • + - - - -
    + + - - + -
  • - +
  • +
    Solr
    +
    + + +
    +
  • + + diff --git a/src/app/partials/dashLoaderShare.html b/src/app/partials/dashLoaderShare.html old mode 100755 new mode 100644 diff --git a/src/app/partials/dashboard.html b/src/app/partials/dashboard.html old mode 100755 new mode 100644 index 10f582360..e3731ab54 --- a/src/app/partials/dashboard.html +++ b/src/app/partials/dashboard.html @@ -1,80 +1,103 @@ -
    +
    - -
    -
    -
    -
    - - - - - - - {{row.title || 'Row '+$index}} -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    -
    -
    + +
    +
    +
    -
    - -
    - -
    -
    - × - Oops! {{panel.error}} -
    -
    - -
    - -
    -
    +
    + + + + + + + {{row.title || 'Row '+$index}} +
    -
    - - - Add panel to empty row - -
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + + + +
    + +
    +
    + + +
    + +
    +
    + × + Oops! {{panel.error}}
    +
    + +
    + +
    -
    -
    -
    - - ADD A ROW - +
    + + + + Add panel to empty row + +
    + +
    +
    +
    + +
    + +
    + + ADD A ROW +
    -
    +
    + +
    + + {{dashboard.current.filterids.length-1}} + + +
    +
    +
    + +
    \ No newline at end of file diff --git a/src/app/partials/dasheditor.html b/src/app/partials/dasheditor.html old mode 100755 new mode 100644 index 5480f37fb..0234bbe72 --- a/src/app/partials/dasheditor.html +++ b/src/app/partials/dasheditor.html @@ -1,245 +1,178 @@ - -