logster 2.20.1 → 3.0.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 (142) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -92
  3. data/README.md +29 -14
  4. data/assets/javascript/main-B82IoCiW.js +1 -0
  5. data/assets/javascript/modules-4-12-BHA4lR2U.js +1 -0
  6. data/assets/javascript/vendor.js +11 -5260
  7. data/assets/logster-config.json +18 -0
  8. data/assets/manifest.json +23 -0
  9. data/assets/stylesheets/main-CgAFFyi8.css +1 -0
  10. data/lib/logster/configuration.rb +1 -0
  11. data/lib/logster/group.rb +2 -2
  12. data/lib/logster/message.rb +4 -4
  13. data/lib/logster/middleware/reporter.rb +34 -3
  14. data/lib/logster/middleware/viewer.rb +205 -33
  15. data/lib/logster/rails/railtie.rb +4 -20
  16. data/lib/logster/redis_store.rb +0 -2
  17. data/lib/logster/version.rb +1 -1
  18. data/lib/logster.rb +1 -1
  19. metadata +17 -186
  20. data/.github/workflows/ci.yml +0 -140
  21. data/.gitignore +0 -3
  22. data/.rubocop.yml +0 -8
  23. data/.streerc +0 -2
  24. data/Gemfile +0 -10
  25. data/Guardfile +0 -10
  26. data/Rakefile +0 -27
  27. data/assets/javascript/.gitkeep +0 -0
  28. data/assets/javascript/chunk.524.c3042190e39d148beaf9.js +0 -22
  29. data/assets/javascript/chunk.582.695dcbfb11a784b110cd.js +0 -22
  30. data/assets/javascript/chunk.747.a730c497582bb6742a6e.js +0 -579
  31. data/assets/javascript/chunk.761.64949d89942c829e5c1b.js +0 -1213
  32. data/assets/javascript/client-app.js +0 -1390
  33. data/assets/stylesheets/.gitkeep +0 -0
  34. data/assets/stylesheets/client-app.css +0 -1
  35. data/assets/stylesheets/vendor.css +0 -1
  36. data/build_client_app.sh +0 -10
  37. data/client-app/.editorconfig +0 -19
  38. data/client-app/.ember-cli +0 -9
  39. data/client-app/.eslintignore +0 -20
  40. data/client-app/.eslintrc +0 -10
  41. data/client-app/.gitignore +0 -23
  42. data/client-app/.prettierignore +0 -21
  43. data/client-app/.prettierrc +0 -1
  44. data/client-app/.template-lintrc.js +0 -10
  45. data/client-app/.watchmanconfig +0 -3
  46. data/client-app/README.md +0 -56
  47. data/client-app/app/app.js +0 -12
  48. data/client-app/app/components/actions-menu.js +0 -50
  49. data/client-app/app/components/back-to-site-link.js +0 -9
  50. data/client-app/app/components/back-trace.js +0 -153
  51. data/client-app/app/components/env-tab.js +0 -68
  52. data/client-app/app/components/message-info.js +0 -151
  53. data/client-app/app/components/message-row.js +0 -46
  54. data/client-app/app/components/page-nav.js +0 -42
  55. data/client-app/app/components/panel-resizer.js +0 -108
  56. data/client-app/app/components/patterns-list.js +0 -142
  57. data/client-app/app/components/tab-contents.js +0 -23
  58. data/client-app/app/components/tabbed-section.js +0 -45
  59. data/client-app/app/components/time-formatter.js +0 -36
  60. data/client-app/app/controllers/index.js +0 -269
  61. data/client-app/app/controllers/show.js +0 -39
  62. data/client-app/app/helpers/logster-url.js +0 -12
  63. data/client-app/app/helpers/or.js +0 -7
  64. data/client-app/app/index.html +0 -31
  65. data/client-app/app/initializers/app-init.js +0 -71
  66. data/client-app/app/lib/decorators.js +0 -13
  67. data/client-app/app/lib/preload.js +0 -43
  68. data/client-app/app/lib/utilities.js +0 -230
  69. data/client-app/app/models/group.js +0 -34
  70. data/client-app/app/models/message-collection.js +0 -303
  71. data/client-app/app/models/message.js +0 -128
  72. data/client-app/app/models/pattern-item.js +0 -32
  73. data/client-app/app/resolver.js +0 -3
  74. data/client-app/app/router.js +0 -13
  75. data/client-app/app/routes/index.js +0 -64
  76. data/client-app/app/routes/settings.js +0 -32
  77. data/client-app/app/routes/show.js +0 -16
  78. data/client-app/app/services/events.js +0 -4
  79. data/client-app/app/styles/app.css +0 -829
  80. data/client-app/app/templates/application.hbs +0 -1
  81. data/client-app/app/templates/components/actions-menu.hbs +0 -31
  82. data/client-app/app/templates/components/back-to-site-link.hbs +0 -8
  83. data/client-app/app/templates/components/back-trace.hbs +0 -15
  84. data/client-app/app/templates/components/env-tab.hbs +0 -10
  85. data/client-app/app/templates/components/message-info.hbs +0 -86
  86. data/client-app/app/templates/components/message-row.hbs +0 -32
  87. data/client-app/app/templates/components/page-nav.hbs +0 -37
  88. data/client-app/app/templates/components/panel-resizer.hbs +0 -3
  89. data/client-app/app/templates/components/patterns-list.hbs +0 -78
  90. data/client-app/app/templates/components/tabbed-section.hbs +0 -18
  91. data/client-app/app/templates/components/time-formatter.hbs +0 -1
  92. data/client-app/app/templates/index.hbs +0 -165
  93. data/client-app/app/templates/settings.hbs +0 -47
  94. data/client-app/app/templates/show.hbs +0 -13
  95. data/client-app/config/ember-cli-update.json +0 -18
  96. data/client-app/config/environment.js +0 -51
  97. data/client-app/config/icons.js +0 -28
  98. data/client-app/config/optional-features.json +0 -6
  99. data/client-app/config/targets.js +0 -26
  100. data/client-app/ember-cli-build.js +0 -28
  101. data/client-app/package.json +0 -76
  102. data/client-app/preload-json-manager.rb +0 -35
  103. data/client-app/public/assets/images/icon_144x144.png +0 -0
  104. data/client-app/public/assets/images/icon_64x64.png +0 -0
  105. data/client-app/testem.js +0 -23
  106. data/client-app/tests/index.html +0 -41
  107. data/client-app/tests/integration/components/back-to-site-link-test.js +0 -20
  108. data/client-app/tests/integration/components/back-trace-test.js +0 -138
  109. data/client-app/tests/integration/components/env-tab-test.js +0 -220
  110. data/client-app/tests/integration/components/message-info-test.js +0 -122
  111. data/client-app/tests/integration/components/patterns-list-test.js +0 -76
  112. data/client-app/tests/test-helper.js +0 -12
  113. data/client-app/tests/unit/controllers/index-test.js +0 -77
  114. data/client-app/tests/unit/controllers/show-test.js +0 -12
  115. data/client-app/tests/unit/routes/index-test.js +0 -11
  116. data/client-app/tests/unit/routes/show-test.js +0 -11
  117. data/client-app/yarn.lock +0 -9905
  118. data/gemfiles/rails_6.1.gemfile +0 -12
  119. data/gemfiles/rails_7.0.gemfile +0 -12
  120. data/gemfiles/rails_7.1.gemfile +0 -9
  121. data/gemfiles/rails_7.2.gemfile +0 -9
  122. data/logster.gemspec +0 -43
  123. data/test/dummy/config/application.rb +0 -31
  124. data/test/dummy/config/boot.rb +0 -6
  125. data/test/dummy/config/environment.rb +0 -6
  126. data/test/examples/test_sidekiq_reporter_example.rb +0 -47
  127. data/test/fake_data/Gemfile +0 -6
  128. data/test/fake_data/generate.rb +0 -23
  129. data/test/logster/middleware/test_reporter.rb +0 -84
  130. data/test/logster/middleware/test_viewer.rb +0 -495
  131. data/test/logster/test_base_store.rb +0 -224
  132. data/test/logster/test_cache.rb +0 -39
  133. data/test/logster/test_defer_logger.rb +0 -36
  134. data/test/logster/test_group.rb +0 -92
  135. data/test/logster/test_ignore_pattern.rb +0 -42
  136. data/test/logster/test_logger.rb +0 -177
  137. data/test/logster/test_message.rb +0 -269
  138. data/test/logster/test_pattern.rb +0 -144
  139. data/test/logster/test_railtie.rb +0 -21
  140. data/test/logster/test_redis_rate_limiter.rb +0 -246
  141. data/test/logster/test_redis_store.rb +0 -1165
  142. data/test/test_helper.rb +0 -44
@@ -1,151 +0,0 @@
1
- import classic from "ember-classic-decorator";
2
- import { bool } from "@ember/object/computed";
3
- import Component from "@ember/component";
4
- import { action, computed } from "@ember/object";
5
- import Preload from "client-app/lib/preload";
6
-
7
- @classic
8
- export default class MessageInfo extends Component {
9
- @bool("currentRow.group") showSolveAllButton;
10
-
11
- @computed("currentMessage.protected", "showSolveAllButton", "showSolveButton")
12
- get buttons() {
13
- const protect = this.currentMessage.protected;
14
- const buttons = [];
15
-
16
- if (!protect && this.showSolveButton) {
17
- buttons.push({
18
- klass: "solve",
19
- action: this.solve,
20
- icon: "check-square",
21
- label: "Solve",
22
- prefix: "far",
23
- danger: true,
24
- });
25
- }
26
-
27
- if (this.showSolveAllButton) {
28
- buttons.push({
29
- klass: "solve-all",
30
- action: this.solveAll,
31
- icon: "check-square",
32
- label: "Solve All",
33
- prefix: "far",
34
- danger: true,
35
- });
36
- }
37
-
38
- if (protect) {
39
- buttons.push({
40
- klass: "unprotect",
41
- action: this.unprotect,
42
- icon: "unlock",
43
- prefix: "fas",
44
- label: "Unprotect",
45
- });
46
- } else {
47
- buttons.push(
48
- {
49
- klass: "remove",
50
- action: this.remove,
51
- icon: "trash-alt",
52
- label: "Remove",
53
- prefix: "far",
54
- danger: true,
55
- },
56
- {
57
- klass: "protect",
58
- action: this.protect,
59
- icon: "lock",
60
- prefix: "fas",
61
- label: "Protect",
62
- }
63
- );
64
- }
65
-
66
- buttons.push({
67
- klass: "copy",
68
- action: this.copy,
69
- icon: "copy",
70
- prefix: "far",
71
- label: "Copy",
72
- });
73
-
74
- return buttons;
75
- }
76
-
77
- @computed("showSolveAllButton", "currentMessage.{canSolve,env}")
78
- get showSolveButton() {
79
- if (this.showSolveAllButton) {
80
- return false;
81
- }
82
- // env isn't loaded until you switch to the env tab
83
- // so if we don't have env we show the button if
84
- // application_version is provided in the config
85
- return this.currentMessage.env
86
- ? this.currentMessage.canSolve
87
- : !!Preload.get("application_version");
88
- }
89
-
90
- @action
91
- copy() {
92
- const header = this.currentMessage.showCount
93
- ? `Message (${this.currentMessage.count} copies reported)`
94
- : "Message";
95
- const message = `${header}\n\n${this.currentMessage.message}`;
96
-
97
- const backtrace = `Backtrace\n\n${this.currentMessage.backtrace}`;
98
-
99
- const httpHosts = Array.isArray(this.currentMessage.env)
100
- ? this.currentMessage.env
101
- .map((e) => e["HTTP_HOST"])
102
- .filter((e, i, a) => e && a.indexOf(e) === i)
103
- .join(", ")
104
- : this.currentMessage.env["HTTP_HOST"];
105
-
106
- const env = httpHosts ? `Env\n\nHTTP HOSTS: ${httpHosts}` : "";
107
- const lines = [message, backtrace, env].filter((l) => l).join("\n\n");
108
-
109
- const temp = document.createElement("TEXTAREA");
110
- document.body.appendChild(temp);
111
- temp.value = lines;
112
- temp.select();
113
- document.execCommand("copy");
114
- document.body.removeChild(temp);
115
- }
116
-
117
- @action
118
- tabChanged(newTab) {
119
- this.onTabChange?.(newTab);
120
- }
121
-
122
- @action
123
- protect() {
124
- this.currentMessage.protect();
125
- }
126
-
127
- @action
128
- unprotect() {
129
- this.currentMessage.unprotect();
130
- }
131
-
132
- @action
133
- remove() {
134
- this.removeMessage(this.currentMessage);
135
- }
136
-
137
- @action
138
- solve() {
139
- this.solveMessage(this.currentMessage);
140
- }
141
-
142
- @action
143
- solveAll() {
144
- this.currentRow.solveAll();
145
- }
146
-
147
- @action
148
- share() {
149
- window.location.pathname = this.currentMessage.shareUrl;
150
- }
151
- }
@@ -1,46 +0,0 @@
1
- import classic from "ember-classic-decorator";
2
- import { classNameBindings, tagName } from "@ember-decorators/component";
3
- import Component from "@ember/component";
4
-
5
- let CHECKED_BOTTOM;
6
- let STICK_TO_BOTTOM;
7
-
8
- @classic
9
- @tagName("div")
10
- @classNameBindings("model.rowClass", ":message-row", "model.selected:selected")
11
- export default class MessageRow extends Component {
12
- willInsertElement() {
13
- super.willInsertElement(...arguments);
14
- if (CHECKED_BOTTOM) {
15
- return;
16
- }
17
-
18
- const topPanel = document.getElementById("top-panel");
19
- if (!topPanel) {
20
- return;
21
- }
22
-
23
- const height = parseFloat(getComputedStyle(topPanel).height);
24
- STICK_TO_BOTTOM = topPanel.scrollHeight - 20 < height + topPanel.scrollTop;
25
- CHECKED_BOTTOM = true;
26
- }
27
-
28
- didInsertElement() {
29
- super.didInsertElement(...arguments);
30
- const topPanel = document.getElementById("top-panel");
31
- if (!topPanel) {
32
- return;
33
- }
34
-
35
- CHECKED_BOTTOM = false;
36
- if (STICK_TO_BOTTOM) {
37
- STICK_TO_BOTTOM = false;
38
- topPanel.scrollTop =
39
- topPanel.scrollHeight - parseFloat(getComputedStyle(topPanel).height);
40
- }
41
- }
42
-
43
- click() {
44
- this.selectRow();
45
- }
46
- }
@@ -1,42 +0,0 @@
1
- import classic from "ember-classic-decorator";
2
- import { classNameBindings, classNames } from "@ember-decorators/component";
3
- import { equal } from "@ember/object/computed";
4
- import Component from "@ember/component";
5
- import { action, computed } from "@ember/object";
6
-
7
- @classic
8
- @classNames("nav-controls")
9
- @classNameBindings("extraClasses")
10
- export default class PageNav extends Component {
11
- @equal("position", 0) disableBackButtons;
12
-
13
- @computed("position", "list.length")
14
- get disableForwardButtons() {
15
- return this.position === this.list.length - 1;
16
- }
17
-
18
- @computed("position")
19
- get displayNumber() {
20
- return this.position + 1;
21
- }
22
-
23
- @action
24
- takeStep(dir) {
25
- const amount = dir === "back" ? -1 : 1;
26
- if (amount === 1 && this.disableForwardButtons) {
27
- return;
28
- }
29
- if (amount === -1 && this.disableBackButtons) {
30
- return;
31
- }
32
-
33
- const newPos = this.position + amount;
34
- this.navigate(newPos);
35
- }
36
-
37
- @action
38
- bigJump(dir) {
39
- const newPos = dir === "back" ? 0 : this.list.length - 1;
40
- this.navigate(newPos);
41
- }
42
- }
@@ -1,108 +0,0 @@
1
- import classic from "ember-classic-decorator";
2
- import { classNames } from "@ember-decorators/component";
3
- import { inject as service } from "@ember/service";
4
- import Component from "@ember/component";
5
- import { scheduleOnce, throttle } from "@ember/runloop";
6
- import { bound } from "client-app/lib/decorators";
7
-
8
- const MOVE_EVENTS = ["touchmove", "mousemove"];
9
- const UP_EVENTS = ["touchend", "mouseup"];
10
- const DOWN_EVENTS = ["touchstart", "mousedown"];
11
-
12
- @classic
13
- @classNames("divider")
14
- export default class PanelResizer extends Component {
15
- @service events;
16
-
17
- resizing = false;
18
-
19
- didInsertElement() {
20
- super.didInsertElement(...arguments);
21
- // inspired by http://plugins.jquery.com/misc/textarea.js
22
- this.set("divider", document.querySelector(".divider"));
23
- for (const name of DOWN_EVENTS) {
24
- this.divider.addEventListener(name, this.dividerClickHandler);
25
- }
26
- scheduleOnce("afterRender", this, "initialDivideView");
27
- }
28
-
29
- willDestroyElement() {
30
- super.willDestroyElement(...arguments);
31
- for (const name of DOWN_EVENTS) {
32
- this.divider.removeEventListener(name, this.dividerClickHandler);
33
- }
34
- }
35
-
36
- initialDivideView() {
37
- const amount = (localStorage && localStorage.logster_divider_bottom) || 300;
38
- const fromTop = window.innerHeight - parseInt(amount, 10);
39
- this.divideView(fromTop);
40
- }
41
-
42
- divideView(fromTop) {
43
- const height = window.innerHeight;
44
- const fromBottom = height - fromTop;
45
-
46
- if (fromTop < 100 || fromTop + 170 > height) {
47
- return;
48
- }
49
-
50
- this.divider.style.bottom = `${fromBottom - 5}px`;
51
- this.events.trigger("panelResized", fromBottom);
52
- }
53
-
54
- @bound
55
- performDrag(e) {
56
- throttle(this, this.throttledPerformDrag, e, 25);
57
- }
58
-
59
- throttledPerformDrag(e) {
60
- if (this.resizing) {
61
- this.divideView(
62
- e.clientY || (e.touches && e.touches[0] && e.touches[0].clientY)
63
- );
64
- }
65
- }
66
-
67
- @bound
68
- endDrag /* e */() {
69
- const overlay = document.getElementById("overlay");
70
- if (overlay) {
71
- overlay.parentElement.removeChild(overlay);
72
- }
73
-
74
- this.set("resizing", false);
75
-
76
- if (localStorage) {
77
- localStorage.logster_divider_bottom = parseInt(
78
- this.divider.style.bottom,
79
- 10
80
- );
81
- }
82
-
83
- for (const name of MOVE_EVENTS) {
84
- document.removeEventListener(name, this.performDrag);
85
- }
86
- for (const name of UP_EVENTS) {
87
- document.removeEventListener(name, this.endDrag);
88
- }
89
- }
90
-
91
- @bound
92
- dividerClickHandler(e) {
93
- e.preventDefault(); // for disabling pull-down-to-refresh on mobile
94
-
95
- const overlay = document.createElement("DIV");
96
- overlay.id = "overlay";
97
- document.body.appendChild(overlay);
98
-
99
- this.set("resizing", true);
100
-
101
- for (const name of MOVE_EVENTS) {
102
- document.addEventListener(name, this.performDrag);
103
- }
104
- for (const name of UP_EVENTS) {
105
- document.addEventListener(name, this.endDrag);
106
- }
107
- }
108
- }
@@ -1,142 +0,0 @@
1
- import classic from "ember-classic-decorator";
2
- import { equal, not } from "@ember/object/computed";
3
- import Component from "@ember/component";
4
- import { action, computed } from "@ember/object";
5
- import Pattern from "client-app/models/pattern-item";
6
- import { ajax } from "client-app/lib/utilities";
7
-
8
- @classic
9
- export default class PatternsList extends Component {
10
- @not("mutable") immutable;
11
- @equal("key", "suppression") showCounter;
12
-
13
- init() {
14
- super.init(...arguments);
15
-
16
- if (this.patterns.length < 1 && this.mutable) {
17
- this.create();
18
- }
19
- }
20
-
21
- @computed("patterns.[]", "newPatterns.[]")
22
- get allPatterns() {
23
- const patterns = this.patterns;
24
- const newPatterns = this.newPatterns || [];
25
- return [...newPatterns.reverse(), ...patterns.reverse()];
26
- }
27
-
28
- makeAPICall(data = {}) {
29
- const { method } = data;
30
- delete data.method;
31
-
32
- return ajax(`/patterns/${this.key}.json`, { method, data });
33
- }
34
-
35
- finallyBlock(pattern) {
36
- pattern.set("saving", false);
37
- }
38
-
39
- catchBlock(pattern, response) {
40
- if (response.responseText) {
41
- pattern.set("error", response.responseText);
42
- } else {
43
- pattern.set("error", "Unknown error occurred. Please see dev console.");
44
- }
45
- }
46
-
47
- requestInit(pattern) {
48
- pattern.setProperties({
49
- saving: true,
50
- error: null,
51
- });
52
- }
53
-
54
- @action
55
- create() {
56
- if (!this.newPatterns) {
57
- this.set("newPatterns", []);
58
- }
59
- this.newPatterns.pushObject(Pattern.create({ isNew: true }));
60
- }
61
-
62
- @action
63
- async trash(pattern) {
64
- if (pattern.isNew) {
65
- this.newPatterns.removeObject(pattern);
66
- pattern.destroy();
67
- return;
68
- }
69
-
70
- this.requestInit(pattern);
71
-
72
- try {
73
- await this.makeAPICall({
74
- method: "DELETE",
75
- pattern: pattern.value,
76
- });
77
-
78
- this.patterns.removeObject(pattern);
79
- pattern.destroy();
80
- } catch (response) {
81
- this.catchBlock(pattern, response);
82
- } finally {
83
- this.finallyBlock(pattern);
84
- }
85
- }
86
-
87
- @action
88
- async save(pattern) {
89
- this.requestInit(pattern);
90
-
91
- try {
92
- if (pattern.isNew) {
93
- const response = await this.makeAPICall({
94
- method: "POST",
95
- pattern: pattern.valueBuffer,
96
- retroactive: !!pattern.retroactive,
97
- });
98
-
99
- pattern.updateValue(response.pattern);
100
- pattern.set("isNew", false);
101
- this.patterns.pushObject(pattern);
102
- this.newPatterns.removeObject(pattern);
103
- } else {
104
- const response = await this.makeAPICall({
105
- method: "PUT",
106
- pattern: pattern.value,
107
- new_pattern: pattern.valueBuffer,
108
- });
109
-
110
- pattern.updateValue(response.pattern);
111
- pattern.set("count", 0);
112
- }
113
- } catch (response) {
114
- this.catchBlock(pattern, response);
115
- } finally {
116
- this.finallyBlock(pattern);
117
- }
118
- }
119
-
120
- @action
121
- async resetCount(pattern) {
122
- pattern.set("saving", true);
123
-
124
- try {
125
- await ajax("/reset-count.json", {
126
- method: "PUT",
127
- data: { pattern: pattern.value, hard: !!pattern.hard },
128
- });
129
-
130
- pattern.set("count", 0);
131
- } catch (response) {
132
- this.catchBlock(pattern, response);
133
- } finally {
134
- this.finallyBlock(pattern);
135
- }
136
- }
137
-
138
- @action
139
- checkboxChanged(pattern) {
140
- pattern.toggleProperty("retroactive");
141
- }
142
- }
@@ -1,23 +0,0 @@
1
- import classic from "ember-classic-decorator";
2
- import { classNameBindings } from "@ember-decorators/component";
3
- import Component from "@ember/component";
4
-
5
- @classic
6
- @classNameBindings("active", ":content", "name")
7
- export default class TabContents extends Component {
8
- isLink = false;
9
-
10
- didInsertElement() {
11
- super.didInsertElement(...arguments);
12
- this.tabActions.addTab(this);
13
-
14
- if (this.defaultTab) {
15
- this.tabActions.selectTab(this);
16
- }
17
- }
18
-
19
- willDestroyElement() {
20
- super.willDestroyElement(...arguments);
21
- this.tabActions.removeTab(this);
22
- }
23
- }
@@ -1,45 +0,0 @@
1
- import classic from "ember-classic-decorator";
2
- import Component from "@ember/component";
3
- import { A } from "@ember/array";
4
- import { action } from "@ember/object";
5
-
6
- @classic
7
- export default class TabbedSection extends Component {
8
- tabs = A();
9
- selected = null;
10
-
11
- @action
12
- selectTab(tab) {
13
- if (tab.isLink) {
14
- this.triggerAction(tab.action);
15
- return;
16
- }
17
-
18
- if (this.selected) {
19
- this.selected.set("active", false);
20
- }
21
-
22
- this.set("selected", tab);
23
- tab.set("active", true);
24
-
25
- this.onTabChange(tab.name);
26
- }
27
-
28
- @action
29
- addTab(tab) {
30
- this.tabs.addObject(tab);
31
-
32
- if (!this.selected && !tab.isLink) {
33
- this.selectTab(tab);
34
- }
35
- }
36
-
37
- @action
38
- removeTab(tab) {
39
- if (this.selected === tab) {
40
- this.set("selected", null);
41
- }
42
-
43
- this.tabs.removeObject(tab);
44
- }
45
- }
@@ -1,36 +0,0 @@
1
- import classic from "ember-classic-decorator";
2
- import { tagName } from "@ember-decorators/component";
3
- import { computed } from "@ember/object";
4
- import Component from "@ember/component";
5
- import { formatTime } from "client-app/lib/utilities";
6
- import { later } from "@ember/runloop";
7
-
8
- const UPDATE_INTERVAL = 60_000;
9
-
10
- @classic
11
- @tagName("")
12
- export default class TimeFormatter extends Component {
13
- didInsertElement() {
14
- super.didInsertElement(...arguments);
15
- later(this, this.updateTime, UPDATE_INTERVAL);
16
- }
17
-
18
- @computed("timestamp")
19
- get title() {
20
- return moment(this.timestamp).format();
21
- }
22
-
23
- @computed("timestamp")
24
- get time() {
25
- return formatTime(this.timestamp);
26
- }
27
-
28
- updateTime() {
29
- if (this.isDestroying || this.isDestroyed) {
30
- return;
31
- }
32
-
33
- this.notifyPropertyChange("timestamp");
34
- later(this, this.updateTime, UPDATE_INTERVAL);
35
- }
36
- }