logster 1.2.11 → 1.3.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +18 -17
- data/.travis.yml +15 -16
- data/CHANGELOG.md +130 -130
- data/Gemfile +4 -4
- data/Guardfile +8 -8
- data/LICENSE.txt +22 -22
- data/README.md +99 -96
- data/Rakefile +24 -23
- data/assets/fonts/FontAwesome.otf +0 -0
- data/assets/fonts/fontawesome-webfont.eot +0 -0
- data/assets/fonts/fontawesome-webfont.svg +639 -639
- data/assets/fonts/fontawesome-webfont.ttf +0 -0
- data/assets/fonts/fontawesome-webfont.woff +0 -0
- data/assets/fonts/fontawesome-webfont.woff2 +0 -0
- data/assets/images/Icon-144_rounded.png +0 -0
- data/assets/images/Icon-144_square.png +0 -0
- data/assets/images/icon_144x144.png +0 -0
- data/assets/images/icon_64x64.png +0 -0
- data/assets/javascript/client-app.js +81 -0
- data/assets/javascript/vendor.js +5302 -0
- data/assets/stylesheets/client-app.css +1 -0
- data/assets/stylesheets/vendor.css +4 -0
- data/build_client_app.sh +12 -0
- data/client-app/.editorconfig +20 -0
- data/client-app/.ember-cli +9 -0
- data/client-app/.eslintignore +19 -0
- data/client-app/.eslintrc.js +46 -0
- data/client-app/.gitignore +23 -0
- data/client-app/.travis.yml +27 -0
- data/client-app/.watchmanconfig +3 -0
- data/client-app/README.md +57 -0
- data/client-app/app/app.js +14 -0
- data/client-app/app/components/message-info.js +18 -0
- data/client-app/app/components/message-row.js +45 -0
- data/client-app/app/components/panel-resizer.js +75 -0
- data/client-app/app/components/tab-contents.js +27 -0
- data/client-app/app/components/tab-link.js +5 -0
- data/client-app/app/components/tabbed-section.js +32 -0
- data/client-app/app/components/time-formatter.js +25 -0
- data/client-app/app/components/update-time.js +21 -0
- data/client-app/app/controllers/index.js +83 -0
- data/client-app/app/controllers/show.js +13 -0
- data/client-app/app/index.html +29 -0
- data/client-app/app/initializers/app-init.js +55 -0
- data/client-app/app/lib/preload.js +14 -0
- data/client-app/app/lib/utilities.js +140 -0
- data/client-app/app/models/message-collection.js +158 -0
- data/client-app/app/models/message.js +99 -0
- data/client-app/app/resolver.js +3 -0
- data/client-app/app/router.js +14 -0
- data/client-app/app/routes/index.js +53 -0
- data/client-app/app/routes/show.js +14 -0
- data/{assets/stylesheets → client-app/app/styles}/app.css +387 -390
- data/{assets/javascript → client-app/app}/templates/application.hbs +2 -2
- data/client-app/app/templates/components/message-info.hbs +44 -0
- data/{assets/javascript → client-app/app/templates}/components/message-row.hbs +17 -17
- data/client-app/app/templates/components/tabbed-section.hbs +10 -0
- data/client-app/app/templates/components/time-formatter.hbs +1 -0
- data/{assets/javascript → client-app/app}/templates/index.hbs +57 -57
- data/{assets/javascript → client-app/app}/templates/show.hbs +4 -4
- data/client-app/config/environment.js +51 -0
- data/client-app/config/optional-features.json +3 -0
- data/client-app/config/targets.js +18 -0
- data/client-app/ember-cli-build.js +29 -0
- data/client-app/package-lock.json +11365 -0
- data/client-app/package.json +56 -0
- data/client-app/testem.js +25 -0
- data/client-app/tests/index.html +34 -0
- data/client-app/tests/integration/components/message-info-test.js +26 -0
- data/client-app/tests/integration/components/message-row-test.js +26 -0
- data/client-app/tests/integration/components/panel-resizer-test.js +26 -0
- data/client-app/tests/integration/components/tab-contents-test.js +26 -0
- data/client-app/tests/integration/components/tab-link-test.js +26 -0
- data/client-app/tests/integration/components/tabbed-section-test.js +26 -0
- data/client-app/tests/integration/components/time-formatter-test.js +26 -0
- data/client-app/tests/integration/components/update-time-test.js +26 -0
- data/client-app/tests/test-helper.js +8 -0
- data/client-app/tests/unit/controllers/index-test.js +12 -0
- data/client-app/tests/unit/controllers/show-test.js +12 -0
- data/client-app/tests/unit/initializers/app-init-test.js +31 -0
- data/client-app/tests/unit/routes/index-test.js +11 -0
- data/client-app/tests/unit/routes/show-test.js +11 -0
- data/lib/examples/sidekiq_logster_reporter.rb +21 -21
- data/lib/logster.rb +54 -54
- data/lib/logster/base_store.rb +130 -130
- data/lib/logster/configuration.rb +25 -25
- data/lib/logster/ignore_pattern.rb +65 -65
- data/lib/logster/logger.rb +102 -101
- data/lib/logster/message.rb +227 -226
- data/lib/logster/middleware/debug_exceptions.rb +26 -26
- data/lib/logster/middleware/reporter.rb +56 -54
- data/lib/logster/middleware/viewer.rb +220 -251
- data/lib/logster/rails/railtie.rb +58 -58
- data/lib/logster/redis_store.rb +481 -477
- data/lib/logster/version.rb +3 -3
- data/lib/logster/web.rb +14 -14
- data/logster.gemspec +34 -33
- data/test/examples/test_sidekiq_reporter_example.rb +46 -46
- data/test/fake_data/Gemfile +4 -4
- data/test/fake_data/generate.rb +10 -10
- data/test/logster/middleware/test_reporter.rb +21 -21
- data/test/logster/middleware/test_viewer.rb +96 -70
- data/test/logster/test_base_store.rb +147 -147
- data/test/logster/test_ignore_pattern.rb +41 -41
- data/test/logster/test_logger.rb +74 -74
- data/test/logster/test_message.rb +34 -34
- data/test/logster/test_redis_rate_limiter.rb +230 -230
- data/test/logster/test_redis_store.rb +427 -414
- data/test/test_helper.rb +38 -37
- data/vendor/assets/javascripts/logster.js.erb +39 -39
- metadata +83 -24
- data/assets/javascript/app.js +0 -817
- data/assets/javascript/components/message-info.hbs +0 -47
- data/assets/javascript/components/panel-resizer.hbs +0 -0
- data/assets/javascript/components/tab-contents.hbs +0 -1
- data/assets/javascript/components/tab-link.hbs +0 -1
- data/assets/javascript/components/tabbed-section.hbs +0 -6
- data/assets/javascript/external/ember-template-compiler.js +0 -22346
- data/assets/javascript/external/ember.js +0 -58500
- data/assets/javascript/external/ember.min.js +0 -17
- data/assets/javascript/external/jquery.min.js +0 -5
- data/assets/javascript/external/lodash.min.js +0 -87
- data/assets/javascript/external/moment.min.js +0 -6
- data/assets/stylesheets/font-awesome.min.css +0 -4
- data/bower.json +0 -25
data/test/test_helper.rb
CHANGED
@@ -1,37 +1,38 @@
|
|
1
|
-
require 'minitest'
|
2
|
-
require 'minitest/unit'
|
3
|
-
require 'minitest/autorun'
|
4
|
-
require 'minitest/pride'
|
5
|
-
require 'redis'
|
6
|
-
require 'logster'
|
7
|
-
require 'logster/base_store'
|
8
|
-
require 'timecop'
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
1
|
+
require 'minitest'
|
2
|
+
require 'minitest/unit'
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'minitest/pride'
|
5
|
+
require 'redis'
|
6
|
+
require 'logster'
|
7
|
+
require 'logster/base_store'
|
8
|
+
require 'timecop'
|
9
|
+
require 'byebug'
|
10
|
+
|
11
|
+
class Logster::TestStore < Logster::BaseStore
|
12
|
+
attr_accessor :reported
|
13
|
+
def initialize
|
14
|
+
@reported = []
|
15
|
+
end
|
16
|
+
|
17
|
+
def save(message)
|
18
|
+
@reported << message
|
19
|
+
end
|
20
|
+
|
21
|
+
def count
|
22
|
+
@reported.count
|
23
|
+
end
|
24
|
+
|
25
|
+
def clear
|
26
|
+
@reported = []
|
27
|
+
end
|
28
|
+
|
29
|
+
def clear_all
|
30
|
+
@reported = []
|
31
|
+
end
|
32
|
+
|
33
|
+
def check_rate_limits(severity)
|
34
|
+
# Do nothing
|
35
|
+
end
|
36
|
+
|
37
|
+
# get, protect, unprotect: unimplemented
|
38
|
+
end
|
@@ -1,39 +1,39 @@
|
|
1
|
-
(function() {
|
2
|
-
var lastReport = null;
|
3
|
-
|
4
|
-
if (!window.Logster) {
|
5
|
-
window.Logster = {
|
6
|
-
enabled: true
|
7
|
-
};
|
8
|
-
}
|
9
|
-
|
10
|
-
window.onerror = function(message, url, line, column, errorObj) {
|
11
|
-
// never bother reporting more than once a minute
|
12
|
-
if (lastReport && new Date() - lastReport < 1000 * 60) {
|
13
|
-
return;
|
14
|
-
}
|
15
|
-
if (!Logster.enabled) {
|
16
|
-
return;
|
17
|
-
}
|
18
|
-
|
19
|
-
lastReport = new Date();
|
20
|
-
|
21
|
-
var err = {
|
22
|
-
message: message,
|
23
|
-
url: url,
|
24
|
-
line: line,
|
25
|
-
column: column,
|
26
|
-
window_location: window.location && (window.location + "")
|
27
|
-
};
|
28
|
-
|
29
|
-
if (errorObj && errorObj.stack) {
|
30
|
-
err.stacktrace = errorObj.stack;
|
31
|
-
}
|
32
|
-
|
33
|
-
$.ajax("<%= Logster.config.subdirectory %>" + "/report_js_error", {
|
34
|
-
data: err,
|
35
|
-
type: "POST",
|
36
|
-
cache: false
|
37
|
-
});
|
38
|
-
};
|
39
|
-
})();
|
1
|
+
(function() {
|
2
|
+
var lastReport = null;
|
3
|
+
|
4
|
+
if (!window.Logster) {
|
5
|
+
window.Logster = {
|
6
|
+
enabled: true
|
7
|
+
};
|
8
|
+
}
|
9
|
+
|
10
|
+
window.onerror = function(message, url, line, column, errorObj) {
|
11
|
+
// never bother reporting more than once a minute
|
12
|
+
if (lastReport && new Date() - lastReport < 1000 * 60) {
|
13
|
+
return;
|
14
|
+
}
|
15
|
+
if (!Logster.enabled) {
|
16
|
+
return;
|
17
|
+
}
|
18
|
+
|
19
|
+
lastReport = new Date();
|
20
|
+
|
21
|
+
var err = {
|
22
|
+
message: message,
|
23
|
+
url: url,
|
24
|
+
line: line,
|
25
|
+
column: column,
|
26
|
+
window_location: window.location && (window.location + "")
|
27
|
+
};
|
28
|
+
|
29
|
+
if (errorObj && errorObj.stack) {
|
30
|
+
err.stacktrace = errorObj.stack;
|
31
|
+
}
|
32
|
+
|
33
|
+
$.ajax("<%= Logster.config.subdirectory %>" + "/report_js_error", {
|
34
|
+
data: err,
|
35
|
+
type: "POST",
|
36
|
+
cache: false
|
37
|
+
});
|
38
|
+
};
|
39
|
+
})();
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logster
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.pre
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- UI for viewing logs in Rack
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-11-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -108,6 +108,20 @@ dependencies:
|
|
108
108
|
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: byebug
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
111
125
|
description: UI for viewing logs in Rack
|
112
126
|
email:
|
113
127
|
- sam.saffron@gmail.com
|
@@ -133,25 +147,70 @@ files:
|
|
133
147
|
- assets/images/Icon-144_square.png
|
134
148
|
- assets/images/icon_144x144.png
|
135
149
|
- assets/images/icon_64x64.png
|
136
|
-
- assets/javascript/app.js
|
137
|
-
- assets/javascript/
|
138
|
-
- assets/
|
139
|
-
- assets/
|
140
|
-
-
|
141
|
-
-
|
142
|
-
-
|
143
|
-
-
|
144
|
-
-
|
145
|
-
-
|
146
|
-
-
|
147
|
-
-
|
148
|
-
-
|
149
|
-
-
|
150
|
-
-
|
151
|
-
-
|
152
|
-
-
|
153
|
-
-
|
154
|
-
-
|
150
|
+
- assets/javascript/client-app.js
|
151
|
+
- assets/javascript/vendor.js
|
152
|
+
- assets/stylesheets/client-app.css
|
153
|
+
- assets/stylesheets/vendor.css
|
154
|
+
- build_client_app.sh
|
155
|
+
- client-app/.editorconfig
|
156
|
+
- client-app/.ember-cli
|
157
|
+
- client-app/.eslintignore
|
158
|
+
- client-app/.eslintrc.js
|
159
|
+
- client-app/.gitignore
|
160
|
+
- client-app/.travis.yml
|
161
|
+
- client-app/.watchmanconfig
|
162
|
+
- client-app/README.md
|
163
|
+
- client-app/app/app.js
|
164
|
+
- client-app/app/components/message-info.js
|
165
|
+
- client-app/app/components/message-row.js
|
166
|
+
- client-app/app/components/panel-resizer.js
|
167
|
+
- client-app/app/components/tab-contents.js
|
168
|
+
- client-app/app/components/tab-link.js
|
169
|
+
- client-app/app/components/tabbed-section.js
|
170
|
+
- client-app/app/components/time-formatter.js
|
171
|
+
- client-app/app/components/update-time.js
|
172
|
+
- client-app/app/controllers/index.js
|
173
|
+
- client-app/app/controllers/show.js
|
174
|
+
- client-app/app/index.html
|
175
|
+
- client-app/app/initializers/app-init.js
|
176
|
+
- client-app/app/lib/preload.js
|
177
|
+
- client-app/app/lib/utilities.js
|
178
|
+
- client-app/app/models/message-collection.js
|
179
|
+
- client-app/app/models/message.js
|
180
|
+
- client-app/app/resolver.js
|
181
|
+
- client-app/app/router.js
|
182
|
+
- client-app/app/routes/index.js
|
183
|
+
- client-app/app/routes/show.js
|
184
|
+
- client-app/app/styles/app.css
|
185
|
+
- client-app/app/templates/application.hbs
|
186
|
+
- client-app/app/templates/components/message-info.hbs
|
187
|
+
- client-app/app/templates/components/message-row.hbs
|
188
|
+
- client-app/app/templates/components/tabbed-section.hbs
|
189
|
+
- client-app/app/templates/components/time-formatter.hbs
|
190
|
+
- client-app/app/templates/index.hbs
|
191
|
+
- client-app/app/templates/show.hbs
|
192
|
+
- client-app/config/environment.js
|
193
|
+
- client-app/config/optional-features.json
|
194
|
+
- client-app/config/targets.js
|
195
|
+
- client-app/ember-cli-build.js
|
196
|
+
- client-app/package-lock.json
|
197
|
+
- client-app/package.json
|
198
|
+
- client-app/testem.js
|
199
|
+
- client-app/tests/index.html
|
200
|
+
- client-app/tests/integration/components/message-info-test.js
|
201
|
+
- client-app/tests/integration/components/message-row-test.js
|
202
|
+
- client-app/tests/integration/components/panel-resizer-test.js
|
203
|
+
- client-app/tests/integration/components/tab-contents-test.js
|
204
|
+
- client-app/tests/integration/components/tab-link-test.js
|
205
|
+
- client-app/tests/integration/components/tabbed-section-test.js
|
206
|
+
- client-app/tests/integration/components/time-formatter-test.js
|
207
|
+
- client-app/tests/integration/components/update-time-test.js
|
208
|
+
- client-app/tests/test-helper.js
|
209
|
+
- client-app/tests/unit/controllers/index-test.js
|
210
|
+
- client-app/tests/unit/controllers/show-test.js
|
211
|
+
- client-app/tests/unit/initializers/app-init-test.js
|
212
|
+
- client-app/tests/unit/routes/index-test.js
|
213
|
+
- client-app/tests/unit/routes/show-test.js
|
155
214
|
- lib/examples/sidekiq_logster_reporter.rb
|
156
215
|
- lib/logster.rb
|
157
216
|
- lib/logster/base_store.rb
|
@@ -195,12 +254,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
195
254
|
version: '0'
|
196
255
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
197
256
|
requirements:
|
198
|
-
- - "
|
257
|
+
- - ">"
|
199
258
|
- !ruby/object:Gem::Version
|
200
|
-
version:
|
259
|
+
version: 1.3.1
|
201
260
|
requirements: []
|
202
261
|
rubyforge_project:
|
203
|
-
rubygems_version: 2.7.
|
262
|
+
rubygems_version: 2.7.7
|
204
263
|
signing_key:
|
205
264
|
specification_version: 4
|
206
265
|
summary: UI for viewing logs in Rack
|
data/assets/javascript/app.js
DELETED
@@ -1,817 +0,0 @@
|
|
1
|
-
moment.lang('en', {
|
2
|
-
relativeTime : {
|
3
|
-
future: "in %s",
|
4
|
-
past: "%s ago",
|
5
|
-
s: "secs",
|
6
|
-
m: "a min",
|
7
|
-
mm: "%d mins",
|
8
|
-
h: "an hr",
|
9
|
-
hh: "%d hrs",
|
10
|
-
d: "a day",
|
11
|
-
dd: "%d days",
|
12
|
-
M: "a mth",
|
13
|
-
MM: "%d mths",
|
14
|
-
y: "a yr",
|
15
|
-
yy: "%d yrs"
|
16
|
-
}
|
17
|
-
});
|
18
|
-
|
19
|
-
|
20
|
-
App = Ember.Application.create({
|
21
|
-
});
|
22
|
-
|
23
|
-
App.ajax = function(url, settings) {
|
24
|
-
settings = settings || {};
|
25
|
-
settings.headers = settings.headers || {};
|
26
|
-
settings.headers["X-SILENCE-LOGGER"] = true;
|
27
|
-
return $.ajax(Logger.rootPath + url, settings);
|
28
|
-
};
|
29
|
-
|
30
|
-
App.preloadOrAjax = function(url, settings) {
|
31
|
-
var preloaded = Logger.preload[url];
|
32
|
-
if (preloaded) {
|
33
|
-
// return a pseudo-XHR
|
34
|
-
return {
|
35
|
-
success: function(callback) {
|
36
|
-
setTimeout(function() {
|
37
|
-
callback(preloaded);
|
38
|
-
}, 0);
|
39
|
-
return this;
|
40
|
-
},
|
41
|
-
error: function() { return this; }
|
42
|
-
};
|
43
|
-
} else {
|
44
|
-
return App.ajax(url, settings);
|
45
|
-
}
|
46
|
-
};
|
47
|
-
|
48
|
-
App.Router.map(function() {
|
49
|
-
this.route("index", { path: "/" });
|
50
|
-
this.route("show", { path: "/show/:id" });
|
51
|
-
});
|
52
|
-
|
53
|
-
var entityMap = {
|
54
|
-
"&": "&",
|
55
|
-
"<": "<",
|
56
|
-
">": ">",
|
57
|
-
'"': '"',
|
58
|
-
"'": ''',
|
59
|
-
"/": '/'
|
60
|
-
};
|
61
|
-
|
62
|
-
function escapeHtml(string) {
|
63
|
-
return String(string).replace(/[&<>"'\/]/g, function (s) {
|
64
|
-
return entityMap[s];
|
65
|
-
});
|
66
|
-
}
|
67
|
-
|
68
|
-
function buildArrayString(array) {
|
69
|
-
var buffer = [];
|
70
|
-
_.each(array, function(v) {
|
71
|
-
if (v === null) {
|
72
|
-
buffer.push('null');
|
73
|
-
} else if (Object.prototype.toString.call(v) === '[object Array]') {
|
74
|
-
buffer.push(buildArrayString(v));
|
75
|
-
} else {
|
76
|
-
buffer.push(escapeHtml(v.toString()));
|
77
|
-
}
|
78
|
-
});
|
79
|
-
return '[' + buffer.join(', ') + ']';
|
80
|
-
}
|
81
|
-
|
82
|
-
function buildHashString(hash, recurse) {
|
83
|
-
if (!hash) return '';
|
84
|
-
|
85
|
-
var buffer = [],
|
86
|
-
hashes = [];
|
87
|
-
_.each(hash, function(v, k) {
|
88
|
-
|
89
|
-
if (v === null) {
|
90
|
-
buffer.push('null');
|
91
|
-
} else if (Object.prototype.toString.call(v) === '[object Array]') {
|
92
|
-
buffer.push("<tr><td>" + escapeHtml(k) + "</td><td>" + buildArrayString(v) + "</td></tr>");
|
93
|
-
} else if (typeof v === "object") {
|
94
|
-
hashes.push(k);
|
95
|
-
} else {
|
96
|
-
buffer.push("<tr><td>" + escapeHtml(k) + "</td><td>" + escapeHtml(v) + "</td></tr>");
|
97
|
-
}
|
98
|
-
});
|
99
|
-
|
100
|
-
if (_.size(hashes) > 0) {
|
101
|
-
_.each(hashes, function(k1) {
|
102
|
-
var v = hash[k1];
|
103
|
-
buffer.push("<tr><td></td><td><table>");
|
104
|
-
buffer.push("<td>" + escapeHtml(k1) + "</td><td>" + buildHashString(v, true) + "</td>");
|
105
|
-
buffer.push("</table></td></tr>");
|
106
|
-
});
|
107
|
-
}
|
108
|
-
var className = recurse?"": "env-table";
|
109
|
-
return "<table class='"+ className +"'>" + buffer.join("\n") + "</table>";
|
110
|
-
}
|
111
|
-
|
112
|
-
App.Message = Ember.Object.extend({
|
113
|
-
|
114
|
-
MAX_LEN: 200,
|
115
|
-
|
116
|
-
expand: function() {
|
117
|
-
this.set("expanded", true);
|
118
|
-
},
|
119
|
-
|
120
|
-
solve: function() {
|
121
|
-
return App.ajax("/solve/" + this.get('key'), { type: "PUT" });
|
122
|
-
},
|
123
|
-
|
124
|
-
"delete": function() {
|
125
|
-
return App.ajax("/message/" + this.get('key'), { type: "DELETE" });
|
126
|
-
},
|
127
|
-
|
128
|
-
protect: function() {
|
129
|
-
this.set('protected', true);
|
130
|
-
return App.ajax("/protect/" + this.get('key'), { type: "PUT" });
|
131
|
-
},
|
132
|
-
unprotect: function() {
|
133
|
-
this.set('protected', false);
|
134
|
-
return App.ajax("/unprotect/" + this.get('key'), { type: "DELETE" });
|
135
|
-
},
|
136
|
-
|
137
|
-
showCount: function() {
|
138
|
-
return this.get('count') > 1;
|
139
|
-
}.property('count'),
|
140
|
-
|
141
|
-
hasMore: function() {
|
142
|
-
var message = this.get("message");
|
143
|
-
var expanded = this.get("expanded");
|
144
|
-
|
145
|
-
return !expanded && message.length > this.MAX_LEN;
|
146
|
-
}.property("message", "expanded"),
|
147
|
-
|
148
|
-
shareUrl: function() {
|
149
|
-
return Logger.rootPath + "/show/" + this.get('key');
|
150
|
-
}.property("key"),
|
151
|
-
|
152
|
-
displayMessage: function() {
|
153
|
-
var message = this.get("message");
|
154
|
-
var expanded = this.get("expanded");
|
155
|
-
|
156
|
-
if (!expanded && message.length > this.MAX_LEN) {
|
157
|
-
message = message.substr(0, this.MAX_LEN);
|
158
|
-
}
|
159
|
-
return message;
|
160
|
-
}.property("message", "expanded"),
|
161
|
-
|
162
|
-
updateFromObject: function(other) {
|
163
|
-
// XXX Only updatable property is count right now
|
164
|
-
this.set('count', other.get('count'));
|
165
|
-
},
|
166
|
-
|
167
|
-
canSolve: function() {
|
168
|
-
var backtrace = this.get("backtrace");
|
169
|
-
return this.get("env.application_version") && backtrace && (backtrace.length > 0);
|
170
|
-
}.property(),
|
171
|
-
|
172
|
-
envTable: function() {
|
173
|
-
return buildHashString(this.get('env'));
|
174
|
-
}.property("env"),
|
175
|
-
|
176
|
-
|
177
|
-
rowClass: function() {
|
178
|
-
switch (this.get("severity")) {
|
179
|
-
case 0:
|
180
|
-
return "debug";
|
181
|
-
case 1:
|
182
|
-
return "info";
|
183
|
-
case 2:
|
184
|
-
return "warn";
|
185
|
-
case 3:
|
186
|
-
return "error";
|
187
|
-
case 4:
|
188
|
-
return "fatal";
|
189
|
-
}
|
190
|
-
}.property("severity"),
|
191
|
-
|
192
|
-
glyph: function() {
|
193
|
-
switch (this.get("severity")) {
|
194
|
-
case 0:
|
195
|
-
return "";
|
196
|
-
case 1:
|
197
|
-
return "";
|
198
|
-
case 2:
|
199
|
-
return "<i class='fa fa-exclamation-circle warning'></i>";
|
200
|
-
case 3:
|
201
|
-
return "<i class='fa fa-times-circle error'></i>";
|
202
|
-
case 4:
|
203
|
-
return "<i class='fa fa-times-circle fatal'></i>";
|
204
|
-
}
|
205
|
-
}.property("severity")
|
206
|
-
});
|
207
|
-
|
208
|
-
App.MessageCollection = Em.Object.extend({
|
209
|
-
|
210
|
-
messages: Em.A(),
|
211
|
-
currentMessage: null,
|
212
|
-
total: 0,
|
213
|
-
|
214
|
-
solve: function(message) {
|
215
|
-
var self = this;
|
216
|
-
message.solve().then(function(){
|
217
|
-
self.reload();
|
218
|
-
});
|
219
|
-
},
|
220
|
-
|
221
|
-
"delete": function(message){
|
222
|
-
var messages = this.get('messages');
|
223
|
-
var idx = messages.indexOf(message);
|
224
|
-
message.delete();
|
225
|
-
message.set('selected', false);
|
226
|
-
this.set('total', this.get('total')-1);
|
227
|
-
this.get('messages').removeObject(message);
|
228
|
-
|
229
|
-
if (idx > 0) {
|
230
|
-
message = messages[idx-1];
|
231
|
-
message.set('selected', true);
|
232
|
-
this.set('currentMessage', message);
|
233
|
-
} else {
|
234
|
-
if (this.get('total') > 0) {
|
235
|
-
message = messages[0];
|
236
|
-
message.set('selected', true);
|
237
|
-
this.set('currentMessage', message);
|
238
|
-
} else {
|
239
|
-
this.reload();
|
240
|
-
}
|
241
|
-
}
|
242
|
-
|
243
|
-
},
|
244
|
-
|
245
|
-
load: function(opts) {
|
246
|
-
var self = this;
|
247
|
-
opts = opts || {};
|
248
|
-
|
249
|
-
var data = {
|
250
|
-
filter: this.get("filter").join("_")
|
251
|
-
};
|
252
|
-
|
253
|
-
search = this.get("search");
|
254
|
-
if (!_.isEmpty(search)) {
|
255
|
-
data.search = search;
|
256
|
-
var regexSearch = this.get("regexSearch");
|
257
|
-
if(regexSearch) {
|
258
|
-
data.regex_search = "true";
|
259
|
-
}
|
260
|
-
}
|
261
|
-
|
262
|
-
if(opts.before){
|
263
|
-
data.before = opts.before;
|
264
|
-
}
|
265
|
-
|
266
|
-
if (opts.after){
|
267
|
-
data.after = opts.after;
|
268
|
-
}
|
269
|
-
|
270
|
-
App.ajax("/messages.json", {
|
271
|
-
data: data
|
272
|
-
}).success(function(data) {
|
273
|
-
// guard against race: ensure the results we're trying to apply
|
274
|
-
// match the current search terms
|
275
|
-
if (Ember.compare(data.filter, self.get('filter')) != 0) { return; }
|
276
|
-
if (Ember.compare(data.search, self.get('search')) != 0) { return; }
|
277
|
-
|
278
|
-
if (data.messages.length > 0) {
|
279
|
-
var newRows = self.toMessages(data.messages);
|
280
|
-
var messages = self.get("messages");
|
281
|
-
if (opts.before) {
|
282
|
-
messages.unshiftObjects(newRows);
|
283
|
-
} else {
|
284
|
-
newRows.forEach(function(nmsg) {
|
285
|
-
messages.forEach(function(emsg, idx) {
|
286
|
-
if (emsg.key == nmsg.key) {
|
287
|
-
messages.removeObject(emsg);
|
288
|
-
if (self.get('currentMessage') === emsg) {
|
289
|
-
// TODO would updateFromJson() work here?
|
290
|
-
self.set('currentMessage', nmsg);
|
291
|
-
nmsg.set('selected', emsg.get('selected'));
|
292
|
-
}
|
293
|
-
}
|
294
|
-
});
|
295
|
-
});
|
296
|
-
messages.addObjects(newRows);
|
297
|
-
if (newRows.length > 0) {
|
298
|
-
App.increaseTitleCount(newRows.length);
|
299
|
-
}
|
300
|
-
}
|
301
|
-
}
|
302
|
-
self.set("total", data.total);
|
303
|
-
});
|
304
|
-
},
|
305
|
-
|
306
|
-
reload: function(){
|
307
|
-
this.set("total", 0);
|
308
|
-
this.get("messages").clear();
|
309
|
-
|
310
|
-
this.load();
|
311
|
-
},
|
312
|
-
|
313
|
-
loadMore: function(){
|
314
|
-
|
315
|
-
var messages = this.get("messages");
|
316
|
-
if (messages.length === 0) {
|
317
|
-
this.load({});
|
318
|
-
return;
|
319
|
-
}
|
320
|
-
|
321
|
-
var lastKey = messages[messages.length-1].get("key");
|
322
|
-
this.load({
|
323
|
-
after: lastKey
|
324
|
-
});
|
325
|
-
},
|
326
|
-
|
327
|
-
moreBefore: function(){
|
328
|
-
return this.get("totalBefore") > 0;
|
329
|
-
}.property("totalBefore"),
|
330
|
-
|
331
|
-
totalBefore: function() {
|
332
|
-
return this.get("total") - this.get("messages").length;
|
333
|
-
}.property("total", "messages.[]"),
|
334
|
-
|
335
|
-
showMoreBefore: function() {
|
336
|
-
var messages = this.get("messages");
|
337
|
-
var firstKey = messages[0].get("key");
|
338
|
-
|
339
|
-
this.load({
|
340
|
-
before: firstKey
|
341
|
-
});
|
342
|
-
},
|
343
|
-
|
344
|
-
regexSearch: function() {
|
345
|
-
search = this.get("search");
|
346
|
-
if( search &&
|
347
|
-
search.length > 2 &&
|
348
|
-
search[0] === "/"
|
349
|
-
){
|
350
|
-
var match = search.match(/\/(.*)\/(.*)/);
|
351
|
-
if(match && match.length === 3){
|
352
|
-
try {
|
353
|
-
return new RegExp(match[1], match[2]);
|
354
|
-
} catch(err) {
|
355
|
-
// don't care
|
356
|
-
}
|
357
|
-
}
|
358
|
-
}
|
359
|
-
}.property("search"),
|
360
|
-
|
361
|
-
toMessages: function(messages){
|
362
|
-
return messages.map(function(m){
|
363
|
-
return App.Message.create(m);
|
364
|
-
});
|
365
|
-
}
|
366
|
-
});
|
367
|
-
|
368
|
-
App.resetTitleCount = function() {
|
369
|
-
App.titleCount = 0;
|
370
|
-
document.title = App.title || document.title;
|
371
|
-
};
|
372
|
-
|
373
|
-
(function(){
|
374
|
-
var hiddenProperty;
|
375
|
-
var visibilitychange;
|
376
|
-
|
377
|
-
$.each(["","webkit","ms","moz","ms"], function(index, prefix){
|
378
|
-
var check = prefix + (prefix === "" ? "hidden" : "Hidden");
|
379
|
-
if(document[check] !== undefined && !hiddenProperty ){
|
380
|
-
hiddenProperty = check;
|
381
|
-
visibilitychange = prefix + "visibilitychange";
|
382
|
-
}
|
383
|
-
});
|
384
|
-
|
385
|
-
App.isHidden = function() {
|
386
|
-
if (hiddenProperty !== undefined){
|
387
|
-
return document[hiddenProperty];
|
388
|
-
} else {
|
389
|
-
return !document.hasFocus;
|
390
|
-
}
|
391
|
-
};
|
392
|
-
|
393
|
-
console.log(visibilitychange);
|
394
|
-
document.addEventListener(visibilitychange, function(){
|
395
|
-
console.log("BLA +" + App.isHidden());
|
396
|
-
if (!App.isHidden()) {
|
397
|
-
App.resetTitleCount();
|
398
|
-
}
|
399
|
-
}, false);
|
400
|
-
})();
|
401
|
-
|
402
|
-
|
403
|
-
App.increaseTitleCount = function(increment){
|
404
|
-
if (!App.isHidden()){
|
405
|
-
return;
|
406
|
-
}
|
407
|
-
App.title = App.title || document.title;
|
408
|
-
App.titleCount = App.titleCount || 0;
|
409
|
-
App.titleCount += increment;
|
410
|
-
document.title = App.title + " (" + App.titleCount + ")";
|
411
|
-
};
|
412
|
-
|
413
|
-
App.IndexRoute = Em.Route.extend({
|
414
|
-
model: function(){
|
415
|
-
// TODO from preload json?
|
416
|
-
return App.MessageCollection.create();
|
417
|
-
},
|
418
|
-
|
419
|
-
setupController: function(controller, model) {
|
420
|
-
this._super(controller, model);
|
421
|
-
controller.setProperties({
|
422
|
-
"showDebug": true,
|
423
|
-
"showInfo": true,
|
424
|
-
"showWarn": true,
|
425
|
-
"showErr": true,
|
426
|
-
"showFatal": true,
|
427
|
-
"search": ''
|
428
|
-
});
|
429
|
-
controller.set("initialized", true);
|
430
|
-
model.reload();
|
431
|
-
|
432
|
-
var times = 0;
|
433
|
-
var backoff = 1;
|
434
|
-
|
435
|
-
this.refreshInterval = setInterval(function(){
|
436
|
-
times += 1;
|
437
|
-
var hidden = App.isHidden();
|
438
|
-
var load = !hidden;
|
439
|
-
|
440
|
-
if (hidden) {
|
441
|
-
if (times % backoff === 0) {
|
442
|
-
load = true;
|
443
|
-
if (backoff<20) { backoff++; }
|
444
|
-
}
|
445
|
-
}
|
446
|
-
// refresh a lot less aggressively in background
|
447
|
-
if (load) {
|
448
|
-
model.loadMore();
|
449
|
-
if (!hidden) {
|
450
|
-
backoff = 1;
|
451
|
-
}
|
452
|
-
}
|
453
|
-
|
454
|
-
}, 3000);
|
455
|
-
},
|
456
|
-
|
457
|
-
deactivate: function(){
|
458
|
-
clearInterval(this.refreshInterval);
|
459
|
-
}
|
460
|
-
});
|
461
|
-
|
462
|
-
App.ShowRoute = Em.Route.extend({
|
463
|
-
model: function(params) {
|
464
|
-
var self = this;
|
465
|
-
return new Promise(function(resolve, reject) {
|
466
|
-
App.preloadOrAjax("/show/" + params.id + ".json").success(function(json) {
|
467
|
-
resolve(App.Message.create(json));
|
468
|
-
}).error(reject);
|
469
|
-
});
|
470
|
-
}
|
471
|
-
});
|
472
|
-
|
473
|
-
App.IndexController = Em.Controller.extend({
|
474
|
-
|
475
|
-
currentMessage: Em.computed.alias('model.currentMessage'),
|
476
|
-
|
477
|
-
actions: {
|
478
|
-
expandMessage: function(message){
|
479
|
-
message.expand();
|
480
|
-
},
|
481
|
-
|
482
|
-
selectMessage: function(message) {
|
483
|
-
var old = this.get("currentMessage");
|
484
|
-
if (old) {
|
485
|
-
old.set("selected",false);
|
486
|
-
}
|
487
|
-
|
488
|
-
message.set('selected', true);
|
489
|
-
this.set('currentMessage', message);
|
490
|
-
},
|
491
|
-
|
492
|
-
showMoreBefore: function(){
|
493
|
-
this.get('model').showMoreBefore();
|
494
|
-
},
|
495
|
-
|
496
|
-
loadMore: function(){
|
497
|
-
return this.get('model').loadMore();
|
498
|
-
},
|
499
|
-
|
500
|
-
clear: function() {
|
501
|
-
var self = this;
|
502
|
-
if (confirm("Clear the logs?\n\nCancel = No, OK = Clear")) {
|
503
|
-
App.ajax("/clear", { type: "POST" }).success(function() {
|
504
|
-
self.get('model').reload();
|
505
|
-
});
|
506
|
-
}
|
507
|
-
},
|
508
|
-
|
509
|
-
removeMessage: function(msg) {
|
510
|
-
var messages = this.get('model');
|
511
|
-
messages.delete(msg);
|
512
|
-
},
|
513
|
-
|
514
|
-
solveMessage: function(msg) {
|
515
|
-
var messages = this.get('model');
|
516
|
-
messages.solve(msg);
|
517
|
-
}
|
518
|
-
},
|
519
|
-
|
520
|
-
filterChanged: function(){
|
521
|
-
var severities = ["Debug", "Info", "Warn", "Err", "Fatal"];
|
522
|
-
var filter = [];
|
523
|
-
for(var i=0; i<5; i++){
|
524
|
-
if(this.get("show" + severities[i])){
|
525
|
-
filter.push(i);
|
526
|
-
}
|
527
|
-
}
|
528
|
-
|
529
|
-
// always show unknown, rare
|
530
|
-
filter.push(5);
|
531
|
-
var model = this.get("model");
|
532
|
-
model.set("filter", filter);
|
533
|
-
if(this.get("initialized")){
|
534
|
-
model.reload();
|
535
|
-
}
|
536
|
-
}.observes(
|
537
|
-
"showDebug",
|
538
|
-
"showInfo",
|
539
|
-
"showWarn",
|
540
|
-
"showErr",
|
541
|
-
"showFatal"
|
542
|
-
),
|
543
|
-
|
544
|
-
searchChanged: function(){
|
545
|
-
var search = this.get("search");
|
546
|
-
var model = this.get("model");
|
547
|
-
model.set("search", search);
|
548
|
-
|
549
|
-
if(this.get("initialized")){
|
550
|
-
model.reload();
|
551
|
-
}
|
552
|
-
}.observes(
|
553
|
-
"search"
|
554
|
-
)
|
555
|
-
|
556
|
-
});
|
557
|
-
|
558
|
-
App.ShowController = Em.Controller.extend({
|
559
|
-
actions: {
|
560
|
-
protect: function(message) {
|
561
|
-
this.get('model').protect();
|
562
|
-
},
|
563
|
-
|
564
|
-
unprotect: function(message) {
|
565
|
-
this.get('model').unprotect();
|
566
|
-
}
|
567
|
-
}
|
568
|
-
});
|
569
|
-
|
570
|
-
App.PanelResizerComponent = Em.Component.extend({
|
571
|
-
classNames: ['divider'],
|
572
|
-
divideView: function(fromTop, win){
|
573
|
-
var $win = win || $(window);
|
574
|
-
var height = $win.height();
|
575
|
-
var fromBottom = $win.height() - fromTop;
|
576
|
-
|
577
|
-
if (fromTop < 100 || fromTop + 100 > height) {
|
578
|
-
return;
|
579
|
-
}
|
580
|
-
|
581
|
-
|
582
|
-
this.topPanel.css("bottom", fromBottom + 5);
|
583
|
-
this.bottomPanel.css("height", fromBottom - 15);
|
584
|
-
this.divider.css("bottom", fromBottom - 5);
|
585
|
-
},
|
586
|
-
|
587
|
-
didInsertElement: function(){
|
588
|
-
var self = this;
|
589
|
-
|
590
|
-
// inspired by http://plugins.jquery.com/misc/textarea.js
|
591
|
-
this.topPanel = $("#top-panel");
|
592
|
-
this.divider = $(".divider");
|
593
|
-
this.bottomPanel = $("#bottom-panel");
|
594
|
-
|
595
|
-
var $win = $(window),
|
596
|
-
resizing = false;
|
597
|
-
|
598
|
-
var performDrag = function(e){
|
599
|
-
if(!resizing) { return; }
|
600
|
-
self.divideView(e.clientY, $win);
|
601
|
-
};
|
602
|
-
|
603
|
-
var endDrag = function(){
|
604
|
-
$("#overlay").remove();
|
605
|
-
resizing = false;
|
606
|
-
|
607
|
-
if(localStorage){
|
608
|
-
localStorage.logster_divider_bottom = parseInt(self.divider.css("bottom"),10);
|
609
|
-
}
|
610
|
-
|
611
|
-
$(document)
|
612
|
-
.unbind('mousemove', performDrag)
|
613
|
-
.unbind('mouseup', endDrag);
|
614
|
-
};
|
615
|
-
|
616
|
-
self.divider.on("mousedown", function(){
|
617
|
-
$("<div id='overlay'></div>").appendTo($("body"));
|
618
|
-
resizing = true;
|
619
|
-
$(document)
|
620
|
-
.mousemove(_.throttle(performDrag,25))
|
621
|
-
.mouseup(endDrag);
|
622
|
-
}).append("<div class='line-1'></div><div class='line-2'></div><div class='line-3'></div>");
|
623
|
-
|
624
|
-
|
625
|
-
Em.run.next(function(){
|
626
|
-
if(localStorage && localStorage.logster_divider_bottom){
|
627
|
-
var fromTop = $win.height() - parseInt(localStorage.logster_divider_bottom,10);
|
628
|
-
self.divideView(fromTop, $win);
|
629
|
-
}
|
630
|
-
});
|
631
|
-
},
|
632
|
-
|
633
|
-
willDestroyElement: function(){
|
634
|
-
$(".divider").off("mousedown");
|
635
|
-
}
|
636
|
-
});
|
637
|
-
|
638
|
-
|
639
|
-
App.MessageRowComponent = Em.Component.extend({
|
640
|
-
|
641
|
-
tagName: "tr",
|
642
|
-
|
643
|
-
classNameBindings: ["model.rowClass", ":message-row", "model.selected:selected"],
|
644
|
-
|
645
|
-
click: function() {
|
646
|
-
this.sendAction('selectedMessage', this.get('model'));
|
647
|
-
},
|
648
|
-
|
649
|
-
willInsertElement: function(){
|
650
|
-
if (App.MessageRowComponent._checkedBottom) {
|
651
|
-
return;
|
652
|
-
}
|
653
|
-
|
654
|
-
var $topPanel = $("#top-panel");
|
655
|
-
|
656
|
-
var scrollTop = $topPanel.scrollTop();
|
657
|
-
var height = $topPanel.height();
|
658
|
-
var scrollHeight = $topPanel[0].scrollHeight;
|
659
|
-
|
660
|
-
App.MessageRowComponent._stickToBottom = scrollHeight - 20 < height + scrollTop;
|
661
|
-
App.MessageRowComponent._checkedBottom = true;
|
662
|
-
},
|
663
|
-
|
664
|
-
didInsertElement: function(){
|
665
|
-
var self = this;
|
666
|
-
var $topPanel = $("#top-panel");
|
667
|
-
Em.run.next(function(){
|
668
|
-
App.MessageRowComponent._checkedBottom = false;
|
669
|
-
|
670
|
-
if (App.MessageRowComponent._stickToBottom){
|
671
|
-
App.MessageRowComponent._stickToBottom = false;
|
672
|
-
$topPanel.scrollTop($topPanel[0].scrollHeight - $topPanel.height());
|
673
|
-
}
|
674
|
-
});
|
675
|
-
}
|
676
|
-
});
|
677
|
-
|
678
|
-
App.UpdateTimeComponent = Em.Component.extend({
|
679
|
-
didInsertElement: function(){
|
680
|
-
var updateTimes = function(){
|
681
|
-
$('.auto-update-time').each(function(){
|
682
|
-
var timestamp = parseInt(this.getAttribute('data-timestamp'),10);
|
683
|
-
var elem = this;
|
684
|
-
|
685
|
-
var text = App.formatTime(timestamp);
|
686
|
-
|
687
|
-
if(text !== elem.innerText) {
|
688
|
-
elem.innerText = text;
|
689
|
-
}
|
690
|
-
|
691
|
-
});
|
692
|
-
Em.run.later(updateTimes, 60000);
|
693
|
-
};
|
694
|
-
|
695
|
-
Em.run.later(updateTimes, 60000);
|
696
|
-
}
|
697
|
-
});
|
698
|
-
|
699
|
-
App.TimeFormatterComponent = Ember.Component.extend({
|
700
|
-
tagName: 'span',
|
701
|
-
classNames: 'auto-update-time',
|
702
|
-
attributeBindings: ['data-timestamp', 'title'],
|
703
|
-
|
704
|
-
title: function(){
|
705
|
-
return this.get('moment').format();
|
706
|
-
}.property(),
|
707
|
-
|
708
|
-
"data-timestamp": function(){
|
709
|
-
return this.get('timestamp');
|
710
|
-
}.property(),
|
711
|
-
|
712
|
-
moment: function(){
|
713
|
-
return moment(this.get("timestamp"));
|
714
|
-
}.property(),
|
715
|
-
|
716
|
-
render: function(buffer){
|
717
|
-
buffer.push(App.formatTime(this.get('timestamp')));
|
718
|
-
},
|
719
|
-
});
|
720
|
-
|
721
|
-
App.formatTime = function(timestamp){
|
722
|
-
var formatted;
|
723
|
-
var time = moment(timestamp);
|
724
|
-
var now = moment();
|
725
|
-
|
726
|
-
if (time.diff(now.startOf('day')) > 0) {
|
727
|
-
formatted = time.format('h:mm a');
|
728
|
-
} else {
|
729
|
-
if (time.diff(now.startOf('week')) > 0) {
|
730
|
-
formatted = time.format('dd h:mm a');
|
731
|
-
} else {
|
732
|
-
if (time.diff(now.startOf('year')) > 0) {
|
733
|
-
formatted = time.format('D MMM h:mm a');
|
734
|
-
} else {
|
735
|
-
formatted = time.format('D MMM YY');
|
736
|
-
}
|
737
|
-
}
|
738
|
-
}
|
739
|
-
|
740
|
-
return formatted;
|
741
|
-
};
|
742
|
-
|
743
|
-
App.TabbedSectionComponent = Ember.Component.extend({
|
744
|
-
tabs: Em.A(),
|
745
|
-
selectTab: function(view) {
|
746
|
-
if (view.get('isLink')) {
|
747
|
-
this.triggerAction(view.get('action'));
|
748
|
-
return;
|
749
|
-
}
|
750
|
-
|
751
|
-
var selected = this.get("selected");
|
752
|
-
if (selected) {
|
753
|
-
selected.set("active", false);
|
754
|
-
}
|
755
|
-
this.set("selected", view);
|
756
|
-
view.set("active", true);
|
757
|
-
},
|
758
|
-
addTab: function(tab) {
|
759
|
-
this.get("tabs").addObject(tab);
|
760
|
-
if (!this.get("selected") && !tab.get('isLink')) {
|
761
|
-
this.selectTab(tab);
|
762
|
-
}
|
763
|
-
},
|
764
|
-
removeTab: function(tab) {
|
765
|
-
if (this.get("selected") === tab) {
|
766
|
-
this.set("selected", null);
|
767
|
-
}
|
768
|
-
this.get("tabs").removeObject(tab);
|
769
|
-
}
|
770
|
-
});
|
771
|
-
|
772
|
-
App.TabContentsComponent = Ember.Component.extend({
|
773
|
-
classNameBindings: ["active", ":content"],
|
774
|
-
isLink: false,
|
775
|
-
|
776
|
-
invokeParent: function(name) {
|
777
|
-
var current = this.get("parentView");
|
778
|
-
while (current && !current[name]) {
|
779
|
-
current = current.get("parentView");
|
780
|
-
}
|
781
|
-
if (current) {
|
782
|
-
current[name](this);
|
783
|
-
}
|
784
|
-
},
|
785
|
-
|
786
|
-
didInsertElement: function() {
|
787
|
-
this.invokeParent("addTab");
|
788
|
-
if (this.get("defaultTab")) {
|
789
|
-
this.invokeParent("selectTab");
|
790
|
-
}
|
791
|
-
},
|
792
|
-
willDestroyElement: function() {
|
793
|
-
this.invokeParent("removeTab");
|
794
|
-
},
|
795
|
-
|
796
|
-
});
|
797
|
-
|
798
|
-
App.MessageInfoComponent = Ember.Component.extend({
|
799
|
-
actions: {
|
800
|
-
protect: function(){
|
801
|
-
this.get('currentMessage').protect();
|
802
|
-
},
|
803
|
-
unprotect: function(){
|
804
|
-
this.get('currentMessage').unprotect();
|
805
|
-
},
|
806
|
-
"remove": function(){
|
807
|
-
this.sendAction("removeMessage", this.get('currentMessage'));
|
808
|
-
},
|
809
|
-
solve: function() {
|
810
|
-
this.sendAction("solveMessage", this.get('currentMessage'));
|
811
|
-
}
|
812
|
-
}
|
813
|
-
});
|
814
|
-
|
815
|
-
App.TabLinkComponent = App.TabContentsComponent.extend({
|
816
|
-
isLink: true
|
817
|
-
});
|