Skip to content

Conversation

Nateowami
Copy link
Collaborator

@Nateowami Nateowami commented May 13, 2025

This is still work in progress, but I want to put it out here as it appears to be working.


This change is Reviewable

@Nateowami Nateowami force-pushed the feature/clean-up-realtime-docs branch 2 times, most recently from abf739b to db6ad5d Compare May 13, 2025 14:36
@Nateowami Nateowami marked this pull request as draft May 13, 2025 14:37
Copy link

codecov bot commented May 13, 2025

Codecov Report

❌ Patch coverage is 71.73913% with 91 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.28%. Comparing base (2033d37) to head (26f7abc).
⚠️ Report is 4 commits behind head on master.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...re/ClientApp/src/xforge-common/realtime.service.ts 43.90% 22 Missing and 1 partial ⚠️
...diagnostic-overlay/diagnostic-overlay.component.ts 0.00% 14 Missing ⚠️
...e/ClientApp/src/app/shared/project-router.guard.ts 29.41% 12 Missing ⚠️
...nx-insights-panel/lynx-insights-panel.component.ts 7.69% 12 Missing ⚠️
...pture/ClientApp/src/app/core/sf-project.service.ts 76.47% 4 Missing ⚠️
...ate/editor/lynx/insights/lynx-workspace.service.ts 25.00% 3 Missing ⚠️
...ture/ClientApp/src/xforge-common/util/rxjs-util.ts 0.00% 3 Missing ⚠️
...ientApp/src/app/core/translation-engine.service.ts 0.00% 2 Missing ⚠️
.../app/serval-administration/draft-jobs.component.ts 0.00% 2 Missing ⚠️
...nslate/editor/note-dialog/note-dialog.component.ts 80.00% 2 Missing ⚠️
... and 9 more
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #3199      +/-   ##
==========================================
+ Coverage   82.18%   82.28%   +0.09%     
==========================================
  Files         611      611              
  Lines       36449    36552     +103     
  Branches     6005     6013       +8     
==========================================
+ Hits        29957    30075     +118     
+ Misses       5623     5590      -33     
- Partials      869      887      +18     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@Nateowami Nateowami force-pushed the feature/clean-up-realtime-docs branch 2 times, most recently from 9fcd8f8 to 74cce2c Compare May 13, 2025 15:47
@Nateowami Nateowami force-pushed the feature/clean-up-realtime-docs branch 2 times, most recently from e689f5d to 9d7185b Compare August 7, 2025 21:57
@Nateowami Nateowami force-pushed the feature/clean-up-realtime-docs branch 2 times, most recently from e689f5d to 7842d29 Compare August 18, 2025 21:01
@Nateowami Nateowami changed the title Clean up realtime docs when they're no longer needed Dispose realtime docs when no longer in use Aug 18, 2025
@Nateowami Nateowami force-pushed the feature/clean-up-realtime-docs branch from 7842d29 to b990402 Compare August 18, 2025 21:09
@marksvc marksvc force-pushed the feature/clean-up-realtime-docs branch 3 times, most recently from 5a61ab3 to 89e0fd9 Compare September 18, 2025 20:33
@marksvc marksvc changed the title Dispose realtime docs when no longer in use SF-3532 Dispose realtime docs when no longer in use Sep 19, 2025
@marksvc marksvc added will require testing PR should not be merged until testers confirm testing is complete e2e Run e2e tests for this pull request labels Sep 26, 2025
@marksvc
Copy link
Collaborator

marksvc commented Sep 26, 2025

Hello @Nateowami ,

Thank you for your work on this!

Here are some comments on the code.

I find positive names to be easier to understand than negative names, when using boolean logic. I suggest to consider renaming DocSubscription.isUnsubscribed$ to isSubscribed$.

Can you explain more about the use of DocSubscription.unsubscribe() instead of using a destroyRef argument to DocSubscription.constructor? It looks like DestroyRef is for some angular classes, and so if we want to use a DocSubscription in a different situation, we might not have a DestroyRef available, and so we would use DocSubscription.unsubscribe?

Rather than provide DocSubscription.unsubscribe for situations where a DestroyRef|Observable was not provided to DocSubscription.constructor, do you think we could always require clients to do one of

  • Give a DestroyRef that they have.
  • inject a DestroyRef, and pass it to DocSubscription.constructor, and later the DestroyRef gets destroyed when.. when the "corresponding injector is destroyed"; or
  • Pass an Observable, and emit from the Observable when the client wants to unsubscribe.
    I'm thinking this would reduce the complexity and variation of the DocSubscription class. (DocSubscription.unsubscribe could be removed.)
    I might have to have a look at what that looks like to decide if I like it better or worse :).

It looks like if we removed DocSubscription.unsubscribe, and instead had clients pass an Observable, that might look something like

// New client field
private readonly bye$ = new Subject<void>();
...
// Pass in constructor
new DocSubscription('DraftGenerationStepsComponent', this.bye$.asObservable())
...
// New client method
wave(): void {
  this.bye$.next();
  this.bye$.complete();
}

I want to mention that we could further reduce the complexity of DocSubscription by changing the constructor destroyRef argument from DestroyRef | Observable<void> to just Observable<void>. That would give some simplification.
Client code might change from

new DocSubscription('DraftGenerationStepsComponent', this.destroyRef)

to something like

new DocSubscription('DraftGenerationStepsComponent', new Observable(subscriber => this.destroyRef.onDestroy(() => subscriber.next())))

That makes the client code more complex just to simplify DocSubscription.constructor by a couple lines, so I'm not too inclined toward it. But I wanted to mention that idea in case it inspires other ideas.

Sometimes when working in TypeScript it seems like it could be useful to have a standard disposable system. In C#, there is an IDisposable interface, and implementing classes have a dispose() method that is called when the class is going away. In this dispose method you can let go of resources that you were holding onto.
If we had any desire to apply a generic disposal system across the frontend TypeScript application, this might be a good place to implement and do it.
AI suggested some disposal patterns that could be applied, which are

  • Implement our own Disposable interface with a dispose method like C#.
  • Using RxJS Subscription, where we add in each held resource and then in ngOnDestroy or another "dispose" method we let go of the resources.
  • Using Angular DestroyRef. I wonder if we can use this with arbitrary classes, not just with Components and Directives.
  • And of interest, in the future, using might come to TypeScript.

In C#, the IDisposal.dispose method is automatically called if you are using an object and it goes out of scope. (using someResource = foo()) Unfortunately, only the Angular DestroyRef and in-the-future using patterns above would be as automated (at least where we could not rely on ngOnDestroy). Hmm.
Well, do you have any comments on generic disposal ability in the frontend application?

It bothers me to see all the error messages :)
My workstation might start it in 15 s. GHA might start it in 30 s.
@marksvc
Copy link
Collaborator

marksvc commented Sep 30, 2025

@Nateowami Okay, we have a clean run of unit tests and e2e tests.

Copy link
Collaborator Author

@Nateowami Nateowami left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Nateowami reviewed 6 of 132 files at r1, 1 of 9 files at r2, 3 of 3 files at r3.
Reviewable status: 10 of 136 files reviewed, 5 unresolved discussions


src/SIL.XForge.Scripture/ClientApp/e2e/await-application-startup.mts line 7 at r3 (raw file):

const pollUrl = 'http://localhost:5000/projects';
const pollInterval = 17000;

This is already its own PR, so shouldn't be here.


src/SIL.XForge.Scripture/ClientApp/src/app/app.component.spec.ts line 133 at r3 (raw file):

    await env.navigate(['/projects', 'project01']);
    flush();
    env.init();

Should calling flush() be part of env.init()? Or would that not be a good option?


src/SIL.XForge.Scripture/ClientApp/e2e/test_characterization.json line 12 at r3 (raw file):

  "generate_draft": {
    "success": 1,
    "failure": 100

I'm guessing these failures are no longer happening? If so this should be reverted.


src/SIL.XForge.Scripture/ClientApp/e2e/presets.ts line 75 at r3 (raw file):

    showArrow: true,
    outputDir: 'test_output/ci_e2e_test_results',
    maxTries: 50

Why was this changed?


src/SIL.XForge.Scripture/ClientApp/e2e/workflows/community-checking.ts line 177 at r3 (raw file):

    await page.waitForTimeout(500);
  } catch (e) {
    await page.pause();

This should only pause if preset.pauseOnFailure === true

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
e2e Run e2e tests for this pull request will require testing PR should not be merged until testers confirm testing is complete
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants