logster 2.21.0 → 3.0.1

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 (140) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +24 -0
  3. data/README.md +29 -14
  4. data/assets/javascript/main-C9t0S9He.js +1 -0
  5. data/assets/javascript/modules-4-12-BnbZfQQN.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-et5OPj6E.css +1 -0
  10. data/lib/logster/configuration.rb +1 -0
  11. data/lib/logster/middleware/reporter.rb +34 -3
  12. data/lib/logster/middleware/viewer.rb +204 -32
  13. data/lib/logster/rails/railtie.rb +4 -20
  14. data/lib/logster/redis_store.rb +0 -2
  15. data/lib/logster/version.rb +1 -1
  16. data/lib/logster.rb +1 -1
  17. metadata +17 -186
  18. data/.github/workflows/ci.yml +0 -140
  19. data/.gitignore +0 -3
  20. data/.rubocop.yml +0 -12
  21. data/.streerc +0 -2
  22. data/Gemfile +0 -10
  23. data/Guardfile +0 -10
  24. data/Rakefile +0 -24
  25. data/assets/javascript/.gitkeep +0 -0
  26. data/assets/javascript/chunk.524.b7d0b89d25457a72409c.js +0 -22
  27. data/assets/javascript/chunk.582.5a04ae4713e692cd335a.js +0 -22
  28. data/assets/javascript/chunk.747.a730c497582bb6742a6e.js +0 -579
  29. data/assets/javascript/chunk.761.64949d89942c829e5c1b.js +0 -1213
  30. data/assets/javascript/client-app.js +0 -1389
  31. data/assets/stylesheets/.gitkeep +0 -0
  32. data/assets/stylesheets/client-app.css +0 -1
  33. data/assets/stylesheets/vendor.css +0 -1
  34. data/build_client_app.sh +0 -10
  35. data/client-app/.editorconfig +0 -19
  36. data/client-app/.ember-cli +0 -9
  37. data/client-app/.eslintignore +0 -20
  38. data/client-app/.eslintrc +0 -10
  39. data/client-app/.gitignore +0 -23
  40. data/client-app/.prettierignore +0 -21
  41. data/client-app/.prettierrc +0 -1
  42. data/client-app/.template-lintrc.js +0 -10
  43. data/client-app/.watchmanconfig +0 -3
  44. data/client-app/README.md +0 -56
  45. data/client-app/app/app.js +0 -12
  46. data/client-app/app/components/actions-menu.js +0 -50
  47. data/client-app/app/components/back-to-site-link.js +0 -9
  48. data/client-app/app/components/back-trace.js +0 -153
  49. data/client-app/app/components/env-tab.js +0 -68
  50. data/client-app/app/components/message-info.js +0 -151
  51. data/client-app/app/components/message-row.js +0 -46
  52. data/client-app/app/components/page-nav.js +0 -42
  53. data/client-app/app/components/panel-resizer.js +0 -108
  54. data/client-app/app/components/patterns-list.js +0 -142
  55. data/client-app/app/components/tab-contents.js +0 -23
  56. data/client-app/app/components/tabbed-section.js +0 -45
  57. data/client-app/app/components/time-formatter.js +0 -36
  58. data/client-app/app/controllers/index.js +0 -288
  59. data/client-app/app/controllers/show.js +0 -39
  60. data/client-app/app/helpers/logster-url.js +0 -12
  61. data/client-app/app/helpers/or.js +0 -7
  62. data/client-app/app/index.html +0 -31
  63. data/client-app/app/initializers/app-init.js +0 -71
  64. data/client-app/app/lib/decorators.js +0 -13
  65. data/client-app/app/lib/preload.js +0 -43
  66. data/client-app/app/lib/utilities.js +0 -230
  67. data/client-app/app/models/group.js +0 -34
  68. data/client-app/app/models/message-collection.js +0 -303
  69. data/client-app/app/models/message.js +0 -128
  70. data/client-app/app/models/pattern-item.js +0 -32
  71. data/client-app/app/resolver.js +0 -3
  72. data/client-app/app/router.js +0 -13
  73. data/client-app/app/routes/index.js +0 -64
  74. data/client-app/app/routes/settings.js +0 -32
  75. data/client-app/app/routes/show.js +0 -16
  76. data/client-app/app/services/events.js +0 -4
  77. data/client-app/app/styles/app.css +0 -898
  78. data/client-app/app/templates/application.hbs +0 -1
  79. data/client-app/app/templates/components/actions-menu.hbs +0 -31
  80. data/client-app/app/templates/components/back-to-site-link.hbs +0 -8
  81. data/client-app/app/templates/components/back-trace.hbs +0 -15
  82. data/client-app/app/templates/components/env-tab.hbs +0 -10
  83. data/client-app/app/templates/components/message-info.hbs +0 -86
  84. data/client-app/app/templates/components/message-row.hbs +0 -32
  85. data/client-app/app/templates/components/page-nav.hbs +0 -37
  86. data/client-app/app/templates/components/panel-resizer.hbs +0 -3
  87. data/client-app/app/templates/components/patterns-list.hbs +0 -78
  88. data/client-app/app/templates/components/tabbed-section.hbs +0 -18
  89. data/client-app/app/templates/components/time-formatter.hbs +0 -1
  90. data/client-app/app/templates/index.hbs +0 -192
  91. data/client-app/app/templates/settings.hbs +0 -47
  92. data/client-app/app/templates/show.hbs +0 -13
  93. data/client-app/config/ember-cli-update.json +0 -18
  94. data/client-app/config/environment.js +0 -51
  95. data/client-app/config/icons.js +0 -28
  96. data/client-app/config/optional-features.json +0 -6
  97. data/client-app/config/targets.js +0 -26
  98. data/client-app/ember-cli-build.js +0 -34
  99. data/client-app/package.json +0 -76
  100. data/client-app/preload-json-manager.rb +0 -35
  101. data/client-app/public/assets/images/icon_144x144.png +0 -0
  102. data/client-app/public/assets/images/icon_64x64.png +0 -0
  103. data/client-app/testem.js +0 -23
  104. data/client-app/tests/index.html +0 -41
  105. data/client-app/tests/integration/components/back-to-site-link-test.js +0 -20
  106. data/client-app/tests/integration/components/back-trace-test.js +0 -138
  107. data/client-app/tests/integration/components/env-tab-test.js +0 -220
  108. data/client-app/tests/integration/components/message-info-test.js +0 -122
  109. data/client-app/tests/integration/components/patterns-list-test.js +0 -76
  110. data/client-app/tests/test-helper.js +0 -12
  111. data/client-app/tests/unit/controllers/index-test.js +0 -77
  112. data/client-app/tests/unit/controllers/show-test.js +0 -12
  113. data/client-app/tests/unit/routes/index-test.js +0 -11
  114. data/client-app/tests/unit/routes/show-test.js +0 -11
  115. data/client-app/yarn.lock +0 -9905
  116. data/gemfiles/rails_6.1.gemfile +0 -12
  117. data/gemfiles/rails_7.0.gemfile +0 -12
  118. data/gemfiles/rails_7.1.gemfile +0 -9
  119. data/gemfiles/rails_7.2.gemfile +0 -9
  120. data/logster.gemspec +0 -43
  121. data/test/dummy/config/application.rb +0 -31
  122. data/test/dummy/config/boot.rb +0 -6
  123. data/test/dummy/config/environment.rb +0 -6
  124. data/test/examples/test_sidekiq_reporter_example.rb +0 -47
  125. data/test/fake_data/Gemfile +0 -6
  126. data/test/fake_data/generate.rb +0 -23
  127. data/test/logster/middleware/test_reporter.rb +0 -84
  128. data/test/logster/middleware/test_viewer.rb +0 -495
  129. data/test/logster/test_base_store.rb +0 -224
  130. data/test/logster/test_cache.rb +0 -39
  131. data/test/logster/test_defer_logger.rb +0 -36
  132. data/test/logster/test_group.rb +0 -92
  133. data/test/logster/test_ignore_pattern.rb +0 -42
  134. data/test/logster/test_logger.rb +0 -177
  135. data/test/logster/test_message.rb +0 -269
  136. data/test/logster/test_pattern.rb +0 -144
  137. data/test/logster/test_railtie.rb +0 -21
  138. data/test/logster/test_redis_rate_limiter.rb +0 -246
  139. data/test/logster/test_redis_store.rb +0 -1165
  140. data/test/test_helper.rb +0 -66
@@ -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
- }