logster 2.5.1 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -0
  3. data/CHANGELOG.md +9 -0
  4. data/README.md +15 -1
  5. data/Rakefile +1 -0
  6. data/assets/javascript/client-app.js +204 -168
  7. data/assets/javascript/vendor.js +5132 -5833
  8. data/assets/stylesheets/client-app.css +1 -1
  9. data/client-app/.eslintrc.js +17 -5
  10. data/client-app/.travis.yml +4 -3
  11. data/client-app/app/app.js +5 -7
  12. data/client-app/app/components/actions-menu.js +24 -17
  13. data/client-app/app/components/back-trace.js +148 -0
  14. data/client-app/app/components/env-tab.js +16 -12
  15. data/client-app/app/components/message-info.js +84 -7
  16. data/client-app/app/components/message-row.js +13 -15
  17. data/client-app/app/components/panel-resizer.js +63 -45
  18. data/client-app/app/components/patterns-list.js +6 -6
  19. data/client-app/app/components/update-time.js +13 -13
  20. data/client-app/app/controllers/index.js +4 -2
  21. data/client-app/app/index.html +1 -1
  22. data/client-app/app/initializers/app-init.js +1 -1
  23. data/client-app/app/lib/decorators.js +11 -0
  24. data/client-app/app/lib/preload.js +14 -3
  25. data/client-app/app/lib/utilities.js +63 -36
  26. data/client-app/app/models/group.js +6 -1
  27. data/client-app/app/models/message-collection.js +9 -7
  28. data/client-app/app/models/message.js +25 -20
  29. data/client-app/app/router.js +4 -6
  30. data/client-app/app/styles/app.css +18 -4
  31. data/client-app/app/templates/components/actions-menu.hbs +6 -2
  32. data/client-app/app/templates/components/back-trace.hbs +8 -0
  33. data/client-app/app/templates/components/message-info.hbs +7 -2
  34. data/client-app/app/templates/index.hbs +4 -1
  35. data/client-app/config/environment.js +1 -1
  36. data/client-app/config/optional-features.json +4 -1
  37. data/client-app/ember-cli-build.js +2 -3
  38. data/client-app/package-lock.json +9712 -2884
  39. data/client-app/package.json +25 -22
  40. data/client-app/preload-json-manager.rb +62 -0
  41. data/client-app/testem.js +0 -1
  42. data/client-app/tests/index.html +1 -1
  43. data/client-app/tests/integration/components/back-trace-test.js +109 -0
  44. data/client-app/tests/integration/components/message-info-test.js +4 -3
  45. data/client-app/tests/integration/components/patterns-list-test.js +7 -2
  46. data/lib/logster.rb +1 -0
  47. data/lib/logster/base_store.rb +16 -9
  48. data/lib/logster/configuration.rb +12 -2
  49. data/lib/logster/defer_logger.rb +1 -1
  50. data/lib/logster/logger.rb +12 -0
  51. data/lib/logster/message.rb +89 -30
  52. data/lib/logster/middleware/viewer.rb +44 -8
  53. data/lib/logster/redis_store.rb +69 -51
  54. data/lib/logster/suppression_pattern.rb +1 -1
  55. data/lib/logster/version.rb +1 -1
  56. data/logster.gemspec +1 -1
  57. data/test/logster/middleware/test_viewer.rb +100 -0
  58. data/test/logster/test_base_store.rb +16 -0
  59. data/test/logster/test_defer_logger.rb +1 -1
  60. data/test/logster/test_message.rb +142 -54
  61. data/test/logster/test_redis_store.rb +99 -39
  62. metadata +11 -6
@@ -1 +1 @@
1
- .divider,.message-info,.nav-controls.group-nav{border-bottom:1px solid #ddd}body{font-family:Arial,"Liberation Sans","DejaVu Sans",sans-serif;font-size:12px}body.mobile,body.mobile .message{font-size:14px}pre{font-family:"Roboto Mono",Consolas,Monaco,Ubuntu Mono,monospace}table.env-table tbody tr td{border-top:none;line-height:18px;height:18px;vertical-align:top}table.env-table,table.env-table table{border-spacing:0;border-collapse:collapse}table.env-table td{padding-right:5px}tbody tr{width:98%}.message-row{font-family:Roboto;display:flex}.pattern-wrapper .pattern-input,.settings-section .api-error{font-family:Consolas,"Roboto Mono",Monaco,Ubuntu Mono,monospace}.message-row .protected,.message-row .severity{text-align:center;width:25px;flex-grow:0;flex-shrink:0;font-size:12px}.message-row div{border-top:.5px #e9e9e9 solid;padding-top:1px;padding-bottom:1px;line-height:25px}.message-row .count{width:30px;flex-grow:0;flex-shrink:0;padding-right:4px;box-sizing:border-box;font-size:11px;font-weight:700;text-align:right}.message-row .message-body{flex-grow:1;flex-shrink:1;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;font-size:13px}.message-row .time{flex-grow:0;flex-shrink:0;color:#999;vertical-align:top;font-size:12px;padding-right:8px}.action-panel .search,.action-panel i.fa,.btn .fa,.btn span,.pattern-wrapper .shrink,.search-clear-all .clear,input,label span{vertical-align:middle}.message-row:hover{background-color:#f8f8f8;cursor:pointer}.message-row.selected{background-color:#dfdfdf}i.fatal{color:#e00}i.error{color:#900}i.warning{color:#feb800}.debug{color:#777}.btn,.tabs a{text-decoration:none;color:#333}.action-panel .search{border:1px solid #ddd;padding:3px;box-sizing:border-box}#log-table .show-more{text-align:center;height:30px;line-height:30px;text-decoration:none;background-color:#ddd;cursor:pointer;margin-top:8px}#overlay,.divider{cursor:row-resize}#bottom-panel{position:fixed;bottom:0;left:0;right:0;height:300px;background-color:#f1f1f1;padding:0 8px 8px;z-index:2}#bottom-panel.full{position:static;background-color:inherit;height:90%}#bottom-panel.full>div{padding-bottom:40px}#bottom-panel.full .tabs{display:none}#bottom-panel.full .message-info{position:static}#bottom-panel.full .message-info .content{display:block;position:static}#bottom-panel.full button.delete,.hidden{display:none}#bottom-panel.full .save,#bottom-panel.full .share{bottom:10px}#bottom-panel.full .message-actions button{margin-top:8px}#bottom-panel.full .message-actions{position:fixed;height:40px;width:100%;left:0;bottom:0;background-color:#eee;border-top:1px solid #dfdfdf;padding-left:10px}.divider,.tabs{border-top:1px solid #ddd}.message-actions{position:absolute;bottom:5px;right:0;margin-right:10px}.message-actions button{margin-left:5px}.divider{position:fixed;bottom:310px;left:0;right:0;height:15px;background-color:#fafafa}.divider div{margin:auto;width:24px;height:1px;background-color:#ccc;position:relative}.divider .line-1{top:5px}.divider .line-2{top:6px}.divider .line-3{top:7px}#top-panel{position:fixed;top:0;left:0;right:0;bottom:320px;overflow:auto}.action-panel,.message-info,.nav-controls.group-nav{position:absolute;left:0;right:0}.message-info{top:0}#bottom-panel.group-view .message-info{top:43px}.action-panel{bottom:0;font-weight:700}.action-panel input{margin:0}.severity-filters label{margin-right:18px}.search-clear-all .clear{float:right}#log-table{margin:auto;width:99%}.message-info .env-table,.message-info pre{position:relative;margin:5px 10px 10px}#overlay{position:fixed;z-index:99999;top:0;bottom:0;left:0;right:0;opacity:0}.message-info .content,.tabs{position:absolute;left:0;right:0}.message-info .content{top:0;bottom:35px;overflow:auto;display:none}.message-info .content.active{display:block}.tabs{bottom:13px;list-style-type:none;margin:0 0 5px;padding:0 0 0 10px}.tabs a,.tabs li{position:relative}.tabs li{float:left;padding-right:5px;margin:0}.tabs a{top:6px;border:1px solid #ddd;border-top:none;border-bottom-left-radius:5px;border-bottom-right-radius:5px;padding:6px;background-color:#e1e1e1}.tabs a.active{border-top:1px solid #f1f1f1;background-color:#f1f1f1}.btn{display:inline-block;margin:0;padding:5px 12px;font-size:1em;line-height:0;text-align:center;cursor:pointer;transition:all .25s;background-color:#ddd;border:none;font-weight:400}.btn:hover{color:#000;background-color:#ccc}.btn .fa{margin-right:7px}.btn:active{text-shadow:none}.btn.danger:hover{background-color:#c63c1b;color:#eee}.btn.ok{background-color:#3781dc;color:#fff}.btn.ok:hover{background-color:#286dc2;color:#fff}.search-clear-all .clear,.search-clear-all .search{height:100%}.search-clear-all .clear,.search-clear-all .search,.severity-filters label{align-self:center}.search-clear-all .footer-btns .settings{margin:0 7px}.search-clear-all{display:flex;justify-content:space-between}.search-clear-all .search{min-width:0;flex-shrink:2}.footer-btns{flex-grow:0;flex-shrink:0}@media (min-width:770px){.search-clear-all,.severity-filters{height:100%}.more-wrapping,.severity-filters{display:flex}.severity-filters{float:left}.action-panel{padding:10px;box-sizing:border-box;height:42px}.message-info{bottom:42px}}@media (max-width:770px){.severity-filters{padding:10px}.search-clear-all{padding:0 10px 10px}.action-panel{height:69px}.message-info{bottom:69px}}@media (max-width:430px){.severity-filters{overflow-x:scroll;overflow-y:hidden;white-space:nowrap}.more-wrapping:after,.more-wrapping:before{content:"";position:absolute;height:18px}.more-wrapping:before{width:15px;margin-left:-10px;background:linear-gradient(to right,#f1f1f1 0,rgba(241,241,241,.001) 100%)}.more-wrapping:after{right:0;width:23px;background:linear-gradient(to left,#f1f1f1 0,rgba(241,241,241,.001) 100%)}}.btn.no-text .fa{margin:0}.btn[disabled]{opacity:.5}.actions-menu{position:absolute;background:#fafafa;display:inline-flex;flex-direction:column;bottom:27px;right:45px;width:115px;padding:5px 5px 0;box-shadow:0 4px 14px rgba(0,0,0,.15);z-index:3}.actions-menu button{margin:0 0 5px;height:27px}.nav-controls{padding:10px}#bottom-panel:not(.full) .nav-controls.env-nav{position:sticky;position:-webkit-sticky;position:-moz-sticky;position:-ms-sticky;position:-o-sticky;top:0;background:#f1f1f1;z-index:1;border-bottom:1px solid #ddd}.current-number{margin:0 7px}.expand-list{text-decoration:underline;color:#00f;cursor:pointer}.settings-page{max-width:1110px;margin-right:auto;margin-left:auto;font-size:15px;padding:0 10px 70px}.settings-header{display:flex;align-items:center;margin-bottom:5px}.settings-header .header-title{flex-grow:1}.settings-header .header-logo{width:50px;height:50px}.settings-section{border-top:1px solid #ddd;padding-top:15px}.settings-section .section-title{margin-top:0}.settings-section .subsection-title{margin-bottom:10px}.settings-section .tip{font-style:italic;font-size:13px;color:grey}.settings-section .pattern-wrapper{margin-top:10px;font-size:16px;display:flex;height:33px}.settings-section .api-error{margin-top:5px;color:red}.pattern-wrapper .pattern-input{width:600px;font-size:inherit;padding:5px 0;height:100%;box-sizing:border-box;vertical-align:middle;flex-grow:1;flex-shrink:1}.retro-checkbox .checkbox{margin:0}.retro-checkbox{margin-top:7px;margin-bottom:15px}.btn.new-pattern{height:100%;line-height:18px}.pattern-wrapper .shrink{height:100%;width:40px;text-align:center;box-sizing:border-box;flex-grow:0;flex-shrink:0;margin-left:10px}.fa{opacity:.7}.pattern-wrapper .shrink.reset{background:unset;width:unset;padding:0;margin-left:8px}.grouping-patterns button.new-pattern{margin-top:10px}
1
+ .divider,.message-info,.nav-controls.group-nav{border-bottom:1px solid #ddd}body{font-family:Arial,"Liberation Sans","DejaVu Sans",sans-serif;font-size:12px}body.mobile,body.mobile .message{font-size:14px}pre{font-family:"Roboto Mono",Consolas,Monaco,Ubuntu Mono,monospace}table.env-table tbody tr td{border-top:none;line-height:18px;height:18px;vertical-align:top}table.env-table,table.env-table table{border-spacing:0;border-collapse:collapse}table.env-table td{padding-right:5px}tbody tr{width:98%}.message-row{font-family:Roboto;display:flex}.pattern-wrapper .pattern-input,.settings-section .api-error{font-family:Consolas,"Roboto Mono",Monaco,Ubuntu Mono,monospace}.message-row .protected,.message-row .severity{text-align:center;width:25px;flex-grow:0;flex-shrink:0;font-size:12px}.message-row div{border-top:.5px #e9e9e9 solid;padding-top:1px;padding-bottom:1px;line-height:25px}.message-row .count{width:30px;flex-grow:0;flex-shrink:0;padding-right:4px;box-sizing:border-box;font-size:11px;font-weight:700;text-align:right}.message-row .message-body{flex-grow:1;flex-shrink:1;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;font-size:13px}.message-row .time{flex-grow:0;flex-shrink:0;color:#999;vertical-align:top;font-size:12px;padding-right:8px}.action-panel .search,.action-panel i.fa,.btn .fa,.btn span,.pattern-wrapper .shrink,.search-clear-all .clear,input,label span{vertical-align:middle}.message-row:hover{background-color:#f8f8f8;cursor:pointer}.message-row.selected{background-color:#dfdfdf}i.fatal{color:#e00}i.error{color:#900}i.warning{color:#feb800}.debug{color:#777}.btn,.tabs a{text-decoration:none;color:#333}.action-panel .search{border:1px solid #ddd;padding:3px;box-sizing:border-box}#log-table .show-more{text-align:center;height:30px;line-height:30px;text-decoration:none;background-color:#ddd;cursor:pointer;margin-top:8px}#overlay,.divider{cursor:row-resize}#bottom-panel{position:fixed;bottom:0;left:0;right:0;height:300px;background-color:#f1f1f1;padding:0 8px 8px;z-index:2}#bottom-panel.full{position:static;background-color:inherit;height:90%}#bottom-panel.full>div{padding-bottom:40px}#bottom-panel.full .tabs{display:none}#bottom-panel.full .message-info{position:static}#bottom-panel.full .message-info .content{display:block;position:static}#bottom-panel.full button.delete,.hidden{display:none}#bottom-panel.full .save,#bottom-panel.full .share{bottom:10px}#bottom-panel.full .message-actions button{margin-top:8px}@media (max-width:382px){#bottom-panel.full .message-actions{height:73px}}@media (min-width:383px){#bottom-panel.full .message-actions{height:40px}}#bottom-panel.full .message-actions{position:fixed;width:100%;left:0;bottom:0;background-color:#eee;border-top:1px solid #dfdfdf;padding-left:10px}.divider,.tabs{border-top:1px solid #ddd}.message-actions{position:absolute;bottom:5px;right:0;margin-right:10px}.message-actions button{margin-left:5px}.divider{position:fixed;bottom:310px;left:0;right:0;height:15px;background-color:#fafafa}.divider div{margin:auto;width:24px;height:1px;background-color:#ccc;position:relative}.divider .line-1{top:5px}.divider .line-2{top:6px}.divider .line-3{top:7px}#top-panel{position:fixed;top:0;left:0;right:0;bottom:320px;overflow:auto}.action-panel,.message-info,.nav-controls.group-nav{position:absolute;left:0;right:0}.message-info{top:0}#bottom-panel.group-view .message-info{top:43px}.action-panel{bottom:0;font-weight:700}.action-panel input{margin:0}.severity-filters label{margin-right:18px}.search-clear-all .clear{float:right}#log-table{margin:auto;width:99%}.message-info .env-table,.message-info pre{position:relative;margin:5px 10px 10px}#overlay{position:fixed;z-index:99999;top:0;bottom:0;left:0;right:0;opacity:0}.message-info .content,.tabs{position:absolute;left:0;right:0}.message-info .content{top:0;bottom:35px;overflow:auto;display:none}.message-info .content.active{display:block}.tabs{bottom:13px;list-style-type:none;margin:0 0 5px;padding:0 0 0 10px}.tabs a,.tabs li{position:relative}.tabs li{float:left;padding-right:5px;margin:0}.tabs a{top:6px;border:1px solid #ddd;border-top:none;border-bottom-left-radius:5px;border-bottom-right-radius:5px;padding:6px;background-color:#e1e1e1}.tabs a.active{border-top:1px solid #f1f1f1;background-color:#f1f1f1}.btn{display:inline-block;margin:0;padding:5px 12px;font-size:1em;line-height:0;text-align:center;cursor:pointer;transition:all .25s;background-color:#ddd;border:none;font-weight:400}.btn:hover{color:#000;background-color:#ccc}.btn .fa{margin-right:7px}.btn:active{text-shadow:none}.btn.danger:hover{background-color:#c63c1b;color:#eee}.btn.ok{background-color:#3781dc;color:#fff}.btn.ok:hover{background-color:#286dc2;color:#fff}.search-clear-all .clear,.search-clear-all .search{height:100%}.search-clear-all .clear,.search-clear-all .search,.severity-filters label{align-self:center}.search-clear-all .footer-btns .settings{margin:0 7px}.search-clear-all{display:flex;justify-content:space-between}.search-clear-all .search{min-width:0;flex-shrink:2}.footer-btns{flex-grow:0;flex-shrink:0}@media (min-width:771px){.search-clear-all,.severity-filters{height:100%}.more-wrapping,.severity-filters{display:flex}.severity-filters{float:left}.action-panel{padding:10px;box-sizing:border-box;height:42px}.message-info{bottom:42px}}@media (max-width:770px){.severity-filters{padding:10px}.search-clear-all{padding:0 10px 10px}.action-panel{height:69px}.message-info{bottom:69px}}@media (max-width:430px){.severity-filters{overflow-x:scroll;overflow-y:hidden;white-space:nowrap}.more-wrapping:after,.more-wrapping:before{content:"";position:absolute;height:18px}.more-wrapping:before{width:15px;margin-left:-10px;background:linear-gradient(to right,#f1f1f1 0,rgba(241,241,241,.001) 100%)}.more-wrapping:after{right:0;width:23px;background:linear-gradient(to left,#f1f1f1 0,rgba(241,241,241,.001) 100%)}}.btn.no-text .fa{margin:0}.btn[disabled]{opacity:.5}.actions-menu{position:absolute;background:#fafafa;display:inline-flex;flex-direction:column;bottom:27px;right:45px;width:115px;padding:5px 5px 0;box-shadow:0 4px 14px rgba(0,0,0,.15);z-index:3}.actions-menu button{margin:0 0 5px;height:27px}.nav-controls{padding:10px}#bottom-panel:not(.full) .nav-controls.env-nav{position:sticky;position:-webkit-sticky;position:-moz-sticky;position:-ms-sticky;position:-o-sticky;top:0;background:#f1f1f1;z-index:1;border-bottom:1px solid #ddd}.current-number{margin:0 7px}.expand-list{text-decoration:underline;color:#00f;cursor:pointer}.settings-page{max-width:1110px;margin-right:auto;margin-left:auto;font-size:15px;padding:0 10px 70px}.settings-header{display:flex;align-items:center;margin-bottom:5px}.settings-header .header-title{flex-grow:1}.settings-header .header-logo{width:50px;height:50px}.settings-section{padding-top:15px}.settings-section .section-title{margin-top:0}.settings-section .subsection-title{margin-bottom:10px}.settings-section .tip{font-style:italic;font-size:13px;color:grey}.settings-section .pattern-wrapper{margin-top:10px;font-size:16px;display:flex;height:33px}.settings-section .api-error{margin-top:5px;color:red}.pattern-wrapper .pattern-input{width:600px;font-size:inherit;padding:5px 0;height:100%;box-sizing:border-box;vertical-align:middle;flex-grow:1;flex-shrink:1}.retro-checkbox .checkbox{margin:0}.retro-checkbox{margin-top:7px}.btn.new-pattern{height:100%;line-height:18px}.pattern-wrapper .shrink{height:100%;width:40px;text-align:center;box-sizing:border-box;flex-grow:0;flex-shrink:0;margin-left:10px}.fa{opacity:.7}.pattern-wrapper .shrink.reset{background:unset;width:unset;padding:0;margin-left:8px}.grouping-patterns button.new-pattern{margin-top:10px}.backtrace-line .line-link{color:#9e9e9e;margin-left:3px}
@@ -1,8 +1,12 @@
1
1
  module.exports = {
2
2
  root: true,
3
+ parser: 'babel-eslint',
3
4
  parserOptions: {
4
- ecmaVersion: 2017,
5
- sourceType: 'module'
5
+ ecmaVersion: 2018,
6
+ sourceType: 'module',
7
+ ecmaFeatures: {
8
+ legacyDecorators: true
9
+ }
6
10
  },
7
11
  plugins: [
8
12
  'ember'
@@ -21,6 +25,7 @@ module.exports = {
21
25
  browser: true
22
26
  },
23
27
  rules: {
28
+ 'ember/no-jquery': 'error'
24
29
  },
25
30
  overrides: [
26
31
  // node files
@@ -36,13 +41,20 @@ module.exports = {
36
41
  'server/**/*.js'
37
42
  ],
38
43
  parserOptions: {
39
- sourceType: 'script',
40
- ecmaVersion: 2015
44
+ sourceType: 'script'
41
45
  },
42
46
  env: {
43
47
  browser: false,
44
48
  node: true
45
- }
49
+ },
50
+ plugins: ['node'],
51
+ rules: Object.assign({}, require('eslint-plugin-node').configs.recommended.rules, {
52
+ // add your custom rules and overrides for node files here
53
+
54
+ // this can be removed once the following is fixed
55
+ // https://github.com/mysticatea/eslint-plugin-node/issues/77
56
+ 'node/no-unpublished-require': 'off'
57
+ })
46
58
  }
47
59
  ]
48
60
  };
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  language: node_js
3
3
  node_js:
4
- - "6"
4
+ - "8"
5
5
 
6
6
  sudo: false
7
7
  dist: trusty
@@ -18,8 +18,9 @@ env:
18
18
  # See https://git.io/vdao3 for details.
19
19
  - JOBS=1
20
20
 
21
- before_install:
22
- - npm config set spin false
21
+ branches:
22
+ only:
23
+ - master
23
24
 
24
25
  script:
25
26
  - npm run lint:hbs
@@ -3,12 +3,10 @@ import Resolver from "./resolver";
3
3
  import loadInitializers from "ember-load-initializers";
4
4
  import config from "./config/environment";
5
5
 
6
- const App = Application.extend({
7
- modulePrefix: config.modulePrefix,
8
- podModulePrefix: config.podModulePrefix,
9
- Resolver
10
- });
6
+ export default class App extends Application {
7
+ modulePrefix = config.modulePrefix;
8
+ podModulePrefix = config.podModulePrefix;
9
+ Resolver = Resolver;
10
+ }
11
11
 
12
12
  loadInitializers(App, config.modulePrefix);
13
-
14
- export default App;
@@ -1,40 +1,47 @@
1
1
  import Component from "@ember/component";
2
- import { observer } from "@ember/object";
2
+ import { bound } from "client-app/lib/decorators";
3
3
 
4
4
  export default Component.extend({
5
5
  showMenu: false,
6
6
  tagName: "span",
7
7
 
8
- init() {
9
- this._super(...arguments);
10
- this.bindingFunction = this.bindingFunction.bind(this);
11
- },
12
-
13
- bindingFunction(event) {
14
- const context = this.$()[0];
15
- if (!Em.$.contains(context, event.target) && context !== event.target) {
8
+ @bound
9
+ outsideClickHandler(event) {
10
+ if (
11
+ this.element &&
12
+ !this.element.contains(event.target) &&
13
+ this.element !== event.target
14
+ ) {
16
15
  this.set("showMenu", false);
16
+ this.updateMenu();
17
17
  }
18
18
  },
19
19
 
20
- bindDocument: observer("showMenu", function() {
21
- const $document = Em.$(document);
22
- if (this.get("showMenu")) {
23
- $document.on("click", this.get("bindingFunction"));
20
+ updateMenu() {
21
+ if (this.showMenu) {
22
+ this.addOutsideClickHandler();
24
23
  } else {
25
- $document.off("click", this.get("bindingFunction"));
24
+ this.removeOutsideClickHandler();
26
25
  }
27
- }),
26
+ },
27
+
28
+ addOutsideClickHandler() {
29
+ document.addEventListener("click", this.outsideClickHandler);
30
+ },
31
+
32
+ removeOutsideClickHandler() {
33
+ document.removeEventListener("click", this.outsideClickHandler);
34
+ },
28
35
 
29
36
  willDestroyElement() {
30
37
  this._super(...arguments);
31
- const $document = Em.$(document);
32
- $document.off("click", this.get("bindingFunction"));
38
+ this.removeOutsideClickHandler();
33
39
  },
34
40
 
35
41
  actions: {
36
42
  expandMenu() {
37
43
  this.toggleProperty("showMenu");
44
+ this.updateMenu();
38
45
  },
39
46
  share() {
40
47
  this.share();
@@ -0,0 +1,148 @@
1
+ import Component from "@ember/component";
2
+ import Preloaded from "client-app/lib/preload";
3
+ import { computed } from "@ember/object";
4
+
5
+ function startsWith(str, search) {
6
+ if (!str || !search || search.length > str.length) {
7
+ return false;
8
+ }
9
+ return str.substring(0, search.length) == search;
10
+ }
11
+
12
+ function backtraceLinksEnabled() {
13
+ return Preloaded.get("backtrace_links_enabled");
14
+ }
15
+
16
+ function appendSlash(str) {
17
+ if (str && str[str.length - 1] !== "/") {
18
+ return str + "/";
19
+ } else {
20
+ return str;
21
+ }
22
+ }
23
+
24
+ function assembleURL({ repo, path, filename, lineNumber, commitSha = null }) {
25
+ let url = appendSlash(repo);
26
+ if (!/\/tree\//.test(url)) {
27
+ url += "blob/";
28
+ url += commitSha ? `${commitSha}/` : "master/";
29
+ }
30
+ url += path + filename;
31
+ if (/^[0-9]+$/.test(lineNumber)) {
32
+ url += `#L${lineNumber}`;
33
+ }
34
+ return url;
35
+ }
36
+
37
+ function shortenLine(line) {
38
+ const isGem = startsWith(line, Preloaded.get("gems_dir"));
39
+ if (isGem) {
40
+ const gemsDir = Preloaded.get("gems_dir");
41
+ return line.substring(gemsDir.length);
42
+ } else {
43
+ return line;
44
+ }
45
+ }
46
+
47
+ export default Component.extend({
48
+ GithubURLForGem(line) {
49
+ let url = null;
50
+ if (!backtraceLinksEnabled()) {
51
+ return url;
52
+ }
53
+
54
+ const regexResults = line.match(/([^/]+)\/(.+\/)(.+):(\d+):.*/);
55
+ const [, gemWithVersion, path, filename, lineNumber] = regexResults || [];
56
+ const gemsData = Preloaded.get("gems_data");
57
+ const match = gemsData
58
+ .filter(g => startsWith(gemWithVersion, `${g.name}-`))
59
+ .sortBy("name.length")
60
+ .reverse()[0];
61
+
62
+ if (match) {
63
+ url = assembleURL({ repo: match.url, path, filename, lineNumber });
64
+ }
65
+ return url;
66
+ },
67
+
68
+ GithubURLForApp(line) {
69
+ let url = null;
70
+
71
+ if (!backtraceLinksEnabled()) {
72
+ return url;
73
+ }
74
+
75
+ const projectDirs = Preloaded.get("directories");
76
+
77
+ const match = projectDirs
78
+ .filter(dir => startsWith(line, dir.path))
79
+ .sortBy("path.length")
80
+ .reverse()[0];
81
+
82
+ if (match) {
83
+ const root = appendSlash(match.path);
84
+ const lineWithoutRoot = line.substring(root.length);
85
+
86
+ let path = "",
87
+ filename,
88
+ lineNumber,
89
+ remaining;
90
+
91
+ const hasSlash = lineWithoutRoot.indexOf("/") !== -1;
92
+ const regex = hasSlash ? /(.+\/)(.+):(\d+)(:.*)/ : /(.+):(\d+)(:.*)/;
93
+
94
+ if (hasSlash) {
95
+ [, path, filename, lineNumber, remaining] =
96
+ lineWithoutRoot.match(regex) || [];
97
+ } else {
98
+ [, filename, lineNumber, remaining] =
99
+ lineWithoutRoot.match(regex) || [];
100
+ }
101
+
102
+ if (filename && lineNumber && remaining) {
103
+ const commitSha = match.main_app ? this.commitSha : null;
104
+
105
+ url = assembleURL({
106
+ repo: match.url,
107
+ path,
108
+ filename,
109
+ lineNumber,
110
+ commitSha
111
+ });
112
+ }
113
+ }
114
+ return url;
115
+ },
116
+
117
+ findGithubURL(line, shortenedLine) {
118
+ const isGem = startsWith(line, Preloaded.get("gems_dir"));
119
+ if (isGem) {
120
+ return this.GithubURLForGem(shortenedLine);
121
+ } else {
122
+ return this.GithubURLForApp(line);
123
+ }
124
+ },
125
+
126
+ commitSha: computed("env", function() {
127
+ let env = null;
128
+ if (Array.isArray(this.env)) {
129
+ env = this.env.map(e => e.application_version).filter(e => e)[0];
130
+ } else if (this.env) {
131
+ env = this.env.application_version;
132
+ }
133
+ return env || Preloaded.get("application_version");
134
+ }),
135
+
136
+ lines: computed("backtrace", "commitSha", function() {
137
+ if (!this.backtrace || this.backtrace.length === 0) {
138
+ return [];
139
+ }
140
+ return this.backtrace.split("\n").map(line => {
141
+ const shortenedLine = shortenLine(line);
142
+ return {
143
+ line: shortenedLine,
144
+ url: this.findGithubURL(line, shortenedLine)
145
+ };
146
+ });
147
+ })
148
+ });
@@ -4,10 +4,6 @@ import { buildHashString } from "client-app/lib/utilities";
4
4
  import Preload from "client-app/lib/preload";
5
5
 
6
6
  export default Component.extend({
7
- didUpdateAttrs() {
8
- this.set("expanded", null);
9
- },
10
-
11
7
  currentEnv: computed("isEnvArray", "currentEnvPosition", function() {
12
8
  if (this.isEnvArray) {
13
9
  return this.message.env[this.currentEnvPosition];
@@ -24,30 +20,38 @@ export default Component.extend({
24
20
  if (!this.isEnvArray) {
25
21
  return buildHashString(this.get("message.env"));
26
22
  } else {
27
- const currentEnv = Em.$.extend({}, this.currentEnv);
28
23
  const expandableKeys = Preload.get("env_expandable_keys") || [];
24
+ const expandedLists = {};
29
25
  expandableKeys.forEach(key => {
30
- if (currentEnv.hasOwnProperty(key) && !Array.isArray(currentEnv[key])) {
31
- const list = [currentEnv[key]];
26
+ if (
27
+ Object.prototype.hasOwnProperty.call(this.currentEnv, key) &&
28
+ !Array.isArray(this.currentEnv[key])
29
+ ) {
30
+ const list = [this.currentEnv[key]];
32
31
  this.message.env.forEach(env => {
33
32
  if (env[key] && list.indexOf(env[key]) === -1) {
34
33
  list.push(env[key]);
35
34
  }
36
35
  });
37
- currentEnv[key] = list.length > 1 ? list : list[0];
36
+ expandedLists[key] = list;
38
37
  }
39
38
  });
40
- return buildHashString(currentEnv, false, this.expanded || []);
39
+ return buildHashString(
40
+ this.currentEnv,
41
+ false,
42
+ this.expanded,
43
+ expandedLists
44
+ );
41
45
  }
42
46
  }),
43
47
 
44
48
  click(e) {
45
- const $elem = Em.$(e.target);
46
- const dataKey = $elem.attr("data-key");
49
+ const elem = e.target;
50
+ const dataKey = elem.dataset.key;
47
51
  const expandableKeys = Preload.get("env_expandable_keys") || [];
48
52
  if (
49
53
  expandableKeys.indexOf(dataKey) !== -1 &&
50
- $elem.hasClass("expand-list")
54
+ elem.classList.contains("expand-list")
51
55
  ) {
52
56
  e.preventDefault();
53
57
  if (!this.expanded) {
@@ -1,13 +1,16 @@
1
1
  import Component from "@ember/component";
2
2
  import { computed } from "@ember/object";
3
+ import Preload from "client-app/lib/preload";
4
+ import { bool } from "@ember/object/computed";
3
5
 
4
6
  export default Component.extend({
5
- buttons: computed("currentMessage.{canSolve,protected}", function() {
6
- const canSolve = this.get("currentMessage.canSolve");
7
+ showSolveAllButton: bool("currentRow.group"),
8
+
9
+ buttons: computed("currentMessage.protected", "showSolveButton", function() {
7
10
  const protect = this.get("currentMessage.protected");
8
11
  const buttons = [];
9
12
 
10
- if (!protect && canSolve) {
13
+ if (!protect && this.showSolveButton) {
11
14
  buttons.push({
12
15
  klass: "solve",
13
16
  action: "solve",
@@ -17,6 +20,16 @@ export default Component.extend({
17
20
  });
18
21
  }
19
22
 
23
+ if (this.showSolveAllButton) {
24
+ buttons.push({
25
+ klass: "solve-all",
26
+ action: "solveAll",
27
+ icon: "check-square-o",
28
+ label: "Solve All",
29
+ danger: true
30
+ });
31
+ }
32
+
20
33
  if (!protect) {
21
34
  buttons.push(
22
35
  {
@@ -42,9 +55,57 @@ export default Component.extend({
42
55
  });
43
56
  }
44
57
 
58
+ buttons.push({
59
+ klass: "copy",
60
+ action: "copyAction",
61
+ icon: "clipboard",
62
+ label: "Copy"
63
+ });
45
64
  return buttons;
46
65
  }),
47
66
 
67
+ showSolveButton: computed(
68
+ "showSolveAllButton",
69
+ "currentMessage.{canSolve,env}",
70
+ function() {
71
+ if (this.showSolveAllButton) return false;
72
+ // env isn't loaded until you switch to the env tab
73
+ // so if we don't have env we show the button if
74
+ // application_version is provided in the config
75
+ return this.currentMessage.env
76
+ ? this.currentMessage.canSolve
77
+ : !!Preload.get("application_version");
78
+ }
79
+ ),
80
+
81
+ copy() {
82
+ const temp = document.createElement("TEXTAREA");
83
+ document.body.appendChild(temp);
84
+ const header = this.currentMessage.showCount
85
+ ? `Message (${this.currentMessage.count} copies reported)`
86
+ : "Message";
87
+ const message = `${header}\n\n${this.currentMessage.message}`;
88
+
89
+ const backtrace = `Backtrace\n\n${this.currentMessage.backtrace
90
+ .split("\n")
91
+ .slice(0, 10)
92
+ .join("\n")}`;
93
+
94
+ const httpHosts = Array.isArray(this.currentMessage.env)
95
+ ? this.currentMessage.env
96
+ .map(e => e["HTTP_HOST"])
97
+ .filter((e, i, a) => e && a.indexOf(e) === i)
98
+ .join(", ")
99
+ : this.currentMessage.env["HTTP_HOST"];
100
+
101
+ const env = httpHosts ? `Env\n\nHTTP HOSTS: ${httpHosts}` : "";
102
+ const lines = [message, backtrace, env].filter(l => l).join("\n\n");
103
+ temp.value = lines;
104
+ temp.select();
105
+ document.execCommand("copy");
106
+ document.body.removeChild(temp);
107
+ },
108
+
48
109
  actions: {
49
110
  tabChanged(newTab) {
50
111
  if (this.onTabChange) {
@@ -53,19 +114,35 @@ export default Component.extend({
53
114
  },
54
115
 
55
116
  protect() {
56
- this.get("currentMessage").protect();
117
+ this.currentMessage.protect();
57
118
  },
119
+
58
120
  unprotect() {
59
- this.get("currentMessage").unprotect();
121
+ this.currentMessage.unprotect();
60
122
  },
123
+
61
124
  remove() {
62
- this.removeMessage(this.get("currentMessage"));
125
+ this.removeMessage(this.currentMessage);
63
126
  },
127
+
64
128
  solve() {
65
- this.solveMessage(this.get("currentMessage"));
129
+ this.solveMessage(this.currentMessage);
66
130
  },
131
+
132
+ solveAll() {
133
+ this.currentRow.solveAll();
134
+ },
135
+
67
136
  share() {
68
137
  window.location.pathname = this.get("currentMessage.shareUrl");
138
+ },
139
+
140
+ copyAction() {
141
+ if (this.fetchEnv && !this.currentMessage.env) {
142
+ this.fetchEnv({ force: true }).then(() => this.copy());
143
+ } else {
144
+ this.copy();
145
+ }
69
146
  }
70
147
  }
71
148
  });