diff --git a/app/components/course-page/test-results-bar/autofix-section/autofix-result.hbs b/app/components/course-page/test-results-bar/autofix-section/autofix-result.hbs
index 40c68f2218..3b73622685 100644
--- a/app/components/course-page/test-results-bar/autofix-section/autofix-result.hbs
+++ b/app/components/course-page/test-results-bar/autofix-section/autofix-result.hbs
@@ -35,14 +35,9 @@
{{#if (eq @autofixRequest.status "in_progress")}}
-
- {{#if this.logstream}}
-
+
+ {{#if this.logstreamContent}}
+
{{/if}}
diff --git a/app/components/course-page/test-results-bar/autofix-section/autofix-result.ts b/app/components/course-page/test-results-bar/autofix-section/autofix-result.ts
index 6d661b27de..8062656ca1 100644
--- a/app/components/course-page/test-results-bar/autofix-section/autofix-result.ts
+++ b/app/components/course-page/test-results-bar/autofix-section/autofix-result.ts
@@ -1,12 +1,10 @@
import AnalyticsEventTrackerService from 'codecrafters-frontend/services/analytics-event-tracker';
-import type Store from '@ember-data/store';
import { action } from '@ember/object';
import { service } from '@ember/service';
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
-import Logstream from 'codecrafters-frontend/utils/logstream';
import type AutofixRequestModel from 'codecrafters-frontend/models/autofix-request';
-import type ActionCableConsumerService from 'codecrafters-frontend/services/action-cable-consumer';
+import type Logstream from 'codecrafters-frontend/utils/logstream';
interface Signature {
Element: HTMLDivElement;
@@ -17,40 +15,21 @@ interface Signature {
}
export default class AutofixResult extends Component
{
- @service declare store: Store;
- @service declare actionCableConsumer: ActionCableConsumerService;
@service declare analyticsEventTracker: AnalyticsEventTrackerService;
- @tracked logstream: Logstream | null = null;
@tracked shouldShowFullLog = false;
+ @tracked logstreamContent: string | null = null;
@tracked diffIsBlurred = true;
@action
- handleDidUpdateAutofixRequestLogstreamId() {
- if (this.logstream && this.args.autofixRequest.logstreamId !== this.logstream.logstreamId) {
- this.logstream.unsubscribe();
- this.handleMarkdownStreamElementInserted(); // create a new logstream
- }
- }
+ handleLogstreamDidUpdate(logstream: Logstream): void {
+ this.logstreamContent = logstream.content;
- @action
- handleLogstreamDidPoll(): void {
+ // TODO: See if we're doing this too often?
+ // Ensure we also reload the autofix request to see whether the status has changed
this.args.autofixRequest.reload();
}
- @action
- handleMarkdownStreamElementInserted() {
- this.logstream = new Logstream(this.args.autofixRequest.logstreamId, this.actionCableConsumer, this.store, this.handleLogstreamDidPoll);
- this.logstream.subscribe();
- }
-
- @action
- handleWillDestroyMarkdownStreamElement() {
- if (this.logstream) {
- this.logstream.unsubscribe();
- }
- }
-
@action
toggleBlur() {
if (this.diffIsBlurred) {
diff --git a/app/modifiers/logstream-did-update.ts b/app/modifiers/logstream-did-update.ts
new file mode 100644
index 0000000000..66cee61f43
--- /dev/null
+++ b/app/modifiers/logstream-did-update.ts
@@ -0,0 +1,50 @@
+// Invokes a callback when a logstream is updated.
+// Usage:
+import type ActionCableConsumerService from 'codecrafters-frontend/services/action-cable-consumer';
+import type Store from '@ember-data/store';
+import Logstream from 'codecrafters-frontend/utils/logstream';
+import Modifier, { type ArgsFor } from 'ember-modifier';
+import { inject as service } from '@ember/service';
+import { registerDestructor } from '@ember/destroyable';
+import type { Owner } from '@ember/test-helpers/build-owner';
+
+interface Signature {
+ Args: {
+ Positional: [(logstream: Logstream) => void, string];
+ };
+}
+
+function cleanup(instance: LogstreamDidUpdateModifier) {
+ if (instance.logstream) {
+ instance.logstream.unsubscribe();
+ instance.logstream = undefined;
+ }
+}
+
+export default class LogstreamDidUpdateModifier extends Modifier {
+ @service declare actionCableConsumer: ActionCableConsumerService;
+ @service declare store: Store;
+
+ logstream?: Logstream;
+
+ constructor(owner: unknown, args: ArgsFor) {
+ super(owner as Owner, args);
+ registerDestructor(this, cleanup);
+ }
+
+ modify(_element: HTMLElement, [callback, logstreamId]: Signature['Args']['Positional']) {
+ cleanup(this);
+
+ this.logstream = new Logstream(logstreamId, this.actionCableConsumer, this.store, () => {
+ callback(this.logstream!);
+ });
+
+ this.logstream.subscribe();
+ }
+}
+
+declare module '@glint/environment-ember-loose/registry' {
+ export default interface Registry {
+ 'logstream-did-update': typeof LogstreamDidUpdateModifier;
+ }
+}
diff --git a/app/utils/logstream.ts b/app/utils/logstream.ts
index 5da6785e7e..28585163b4 100644
--- a/app/utils/logstream.ts
+++ b/app/utils/logstream.ts
@@ -35,10 +35,6 @@ export default class Logstream {
}
subscribeTask = task({ drop: true }, async (): Promise => {
- if (this.isSubscribed) {
- return;
- }
-
this.isTerminated = false;
this.isSubscribed = false;