Skip to content

[Feature/sat] Satellite prediction#879

Draft
MichaelWheeley wants to merge 58 commits intoaccius:Stagingfrom
MichaelWheeley:feature/sat_predict_dev2
Draft

[Feature/sat] Satellite prediction#879
MichaelWheeley wants to merge 58 commits intoaccius:Stagingfrom
MichaelWheeley:feature/sat_predict_dev2

Conversation

@MichaelWheeley
Copy link
Copy Markdown
Contributor

@MichaelWheeley MichaelWheeley commented Apr 5, 2026

What does this PR do?

  • Adds satellite prediction modal.
  • Fixes problem with inability to scroll satellite details window.
  • SatelliteOrbit.js is imported with very minor modification from satvis project, MIT license.

Type of change

  • Bug fix
  • New feature
  • Performance improvement
  • Refactor / code cleanup
  • Documentation
  • Translation
  • Map layer plugin

How to test

  1. select many satellites in the details window such that it overflows the window - it should now be possible to mouse scroll up and down.
  2. From the satellite details window choose the name of any listed satellite, it will open a modal dialog showing satellite prediction for the next 7 days. Press close or escape key to exit the modal.
  3. Change the minimum elevation [deg] in the settings -> satellite menu, e.g. set it to some quite high like 70 degrees, then go back and open a new modal. Only those passes where the minimum is reached are shown, and the duration of the passes (that is the duration above the minimum threshold) will be shorter.
  4. Leave the modal open, the times in the time from now column will decrement each minute.

Checklist

  • App loads without console errors
  • Tested in Dark, Light, and Retro themes
  • Responsive at different screen sizes (desktop + mobile)
  • If touching server.js: caches have TTLs and size caps (we serve 2,000+ concurrent users)
  • If adding an API route: includes caching and error handling
  • If adding a panel: wired into Modern, Classic, and Dockable layouts
  • No hardcoded colors — uses CSS variables (var(--accent-cyan), etc.)
  • No .bak, .old, console.log debug lines, or test scripts included

Screenshots (if visual change)

each satellite listed is now a PREDICT button - press it to get a prediction modal
image

image

@MichaelWheeley MichaelWheeley marked this pull request as ready for review April 5, 2026 05:11
Copy link
Copy Markdown
Owner

@accius accius left a comment

Choose a reason for hiding this comment

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

Good progress on satellite prediction — the pass table and auto-refresh are nice additions. A few things to address:

Must fix

XSS risk in onclick handler — Satellite names and TLE lines are injected unescaped into an inline onclick:

onclick="openSatellitePredict('${sat.name}', '${sat.tle1}', '${sat.tle2}')"

A satellite name containing ' breaks the handler; malicious content is injectable. Use data- attributes with a delegated event listener, or escape the values.

Interval leakwindow.satellitePredictInterval is overwritten if a second modal opens before the first interval fires. The old interval keeps running. Clear the previous one before assigning:

if (window.satellitePredictInterval) clearInterval(window.satellitePredictInterval);

Carries all #877 issues — This PR includes #877's commits, so the hardcoded colors, broken nested <table> HTML, duplicate style attribute, and valueAsNumber ?? fallback bugs all apply here too. Fix those in #877 first.

Should fix

Commented-out code — Large blocks in useSatelliteLayer.js (~30 lines) are commented out rather than removed. Either delete them now or open an issue to track it — don't ship dead code in comments.

Hardcoded button colorsbackground: #440000; border: 1px solid #ff4444 on the satellite name button won't work in Light/Retro themes. Use CSS variables.

Worth discussing

dayjs dependency — Does the project already have date utilities that could handle the format() and diff() calls? Adding a new dependency for a few date operations adds bundle weight. Not a blocker if the team is fine with it.

60s full recomputation — The interval recomputes all orbital passes every minute. Since pass times only shift meaningfully over hours, you could just update the "from now" column without rerunning the orbital math.

color changes
replace ?? with || incase of NaN
minElev default consistency to 5.0
restrict minElev to -5 to 89
…ed legacy code since satellite location calculations are now done as a hook in useSatellites.js
…no longer updated unless modal is reopened or if 'satellites' is updated. Display Time From Now as hours:minutes:seconds
@MichaelWheeley MichaelWheeley marked this pull request as draft April 6, 2026 16:30
Copy link
Copy Markdown
Owner

@accius accius left a comment

Choose a reason for hiding this comment

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

Review — Satellite prediction modal (draft)

Nice feature. A few things to address before exiting draft:

Correctness / safety

  1. String interpolation into onclick is fragile and XSS-adjacent:

    onclick="openSatellitePredict('${sat.name}', '${sat.tle1}', '${sat.tle2}')"

    A satellite name containing a single quote (or a TLE line containing backslash/newlines) will break the handler or allow HTML injection. TLE source is currently trusted, but please switch to a data-attribute + addEventListener pattern, or register the sat by an id lookup in a module-level map and pass only an index.

  2. Invalid HTML — nested <table> inside <table>. The sat-card already wraps everything in one <table>, and the PR opens three more nested <table> elements inside its body, plus a stray trailing </table>. Browsers recover, but layout/paint is unpredictable and it will bite future styling changes. Use <tbody> sections with classes instead.

  3. setInterval memory leak on re-open: window.satellitePredictInterval is overwritten without clearing the previous interval when the user clicks another satellite name while a modal is already open. Clear it at the top of openSatellitePredict unconditionally.

  4. keydown listener leak: handleKeyDown only removes itself on Enter/Escape. Backdrop-click close and the "replace existing modal" path leave the listener attached, and each re-open adds another. Always remove in the cleanup paths.

  5. window.openSatellitePredict never cleaned up in the useEffect return. On hot reload it's fine, but consider returning a cleanup that deletes the global.

  6. generateModalContent(currentPasses) uses the recomputed currentPasses, but the initial render uses passes from an earlier computePassesElevation call. These two calls happen back-to-back with no TLE change — recompute once and use the single array.

Code quality

  1. Inconsistent config access: the component already receives config via useLayer props but the PR adds useAppConfig() to grab globalConfig. Pick one path — mixing them means settings changes won't propagate consistently.

  2. Hardcoded colors (#302115, #233b46, #00f800, #252e17) in the satellite card HTML break theme support. Please use CSS variables per the checklist.

  3. Orbit.js modification from upstream — changing 0.5 → 0.05 in orbitalPeriod skip factor increases compute cost ~10x. Please add a short comment explaining the observed failure mode that motivated it, and consider whether we can keep the upstream default in the non-first-pass path.

  4. computePassesSwath imported from upstream but appears unused in this PR. Drop dead code until needed.

  5. package.json adds dayjs. The repo already uses plain Date/Intl in many places; adding a date lib just for formatting and .add(7, 'day') is heavyweight. Consider Intl.DateTimeFormat + date.getTime() + 7*86400000.

  6. lastElevation is read but reassignment after loop entry is unused in the branch where ongoingPass is true (just noting for future cleanup).

Dependency

  • Stacked on #877. Please mark this ready for review only after #877 lands (or rebase so it's self-contained).

UX

  • Modal width: 50vw will be unusable on mobile — suggest min-width + max-width responsive handling. Checklist has "Responsive at different screen sizes" unchecked.
  • Closing on Enter is surprising; Escape is standard. Suggest dropping Enter.

Direction is great — mostly safety and cleanup needed.

@MichaelWheeley
Copy link
Copy Markdown
Contributor Author

still waiting on #877 before this one is ready for review

@accius in #879 you said April 5,

Must fix

XSS risk in onclick handler — Satellite names and TLE lines are injected unescaped into an inline onclick:

onclick="openSatellitePredict('${sat.name}', '${sat.tle1}', '${sat.tle2}')"

A satellite name containing ' breaks the handler; malicious content is injectable. Use data- attributes with a delegated event listener, or escape the values.

now handled in event listener

Interval leakwindow.satellitePredictInterval is overwritten if a second modal opens before the first interval fires. The old interval keeps running. Clear the previous one before assigning:

if (window.satellitePredictInterval) clearInterval(window.satellitePredictInterval);

done

Carries all #877 issues — This PR includes #877's commits, so the hardcoded colors, broken nested <table> HTML, duplicate style attribute, and valueAsNumber ?? fallback bugs all apply here too. Fix those in #877 first.

changes from previous PR merged

Should fix

Commented-out code — Large blocks in useSatelliteLayer.js (~30 lines) are commented out rather than removed. Either delete them now or open an issue to track it — don't ship dead code in comments.

removed dead code in useSatelliteLayer.js, this appeared to be legacy code, unused because satellite location calculations are now done as a hook in useSatellites.js

Hardcoded button colorsbackground: #440000; border: 1px solid #ff4444 on the satellite name button won't work in Light/Retro themes. Use CSS variables.

Hard-coded colors where removed in earlier PR and merged into this one.

Worth discussing

dayjs dependency — Does the project already have date utilities that could handle the format() and diff() calls? Adding a new dependency for a few date operations adds bundle weight. Not a blocker if the team is fine with it.

use of dayjs completely eliminated, package removed from package.json

60s full recomputation — The interval recomputes all orbital passes every minute. Since pass times only shift meaningfully over hours, you could just update the "from now" column without rerunning the orbital math.

Modified, the intensive satellite calculation now only occurs once as the modal opens. Refresh time is every second and the 'Time From Now' is displayed as +hours:minutes:seconds. Displayed time is replaced with word 'VISIBLE' for a visible satellite, or the whole line is dropped from the table if the satellite has already passed.

@accius You also said April 14,

  1. String interpolation into onclick is fragile and XSS-adjacent:....

duplicate

  1. Invalid HTML — nested <table> inside <table>.....

duplicate

  1. setInterval memory leak on re-open: window.satellitePredictInterval is overwritten without.....

duplicate

  1. keydown listener leak: handleKeyDown only removes itself on Enter/Escape. Backdrop-click close and the "replace existing modal" path leave the listener attached, and each re-open adds another. Always remove in the cleanup paths.

event listeners cleaned-up on exit from main window and from modal.

  1. window.openSatellitePredict never cleaned up in the useEffect return. On hot reload it's fine, but consider returning a cleanup that deletes the global.

clean-up added to window.openSatellitePredict

  1. generateModalContent(currentPasses) uses the recomputed currentPasses, but the initial render uses passes from an earlier computePassesElevation call. These two calls happen back-to-back with no TLE change — recompute once and use the single array.

duplicate

  1. Inconsistent config access: the component already receives config via useLayer props but the PR adds useAppConfig() to grab globalConfig. Pick one path — mixing them means settings changes won't propagate consistently.

removed reference to useAppConfig

  1. Hardcoded colors (#302115, #233b46, #00f800, #252e17) in the satellite card HTML break theme support. Please use CSS variables per the checklist.

duplicate

  1. Orbit.js modification from upstream — changing 0.5 → 0.05 in orbitalPeriod skip factor increases compute cost ~10x. Please add a short comment explaining the observed failure mode that motivated it, and consider whether we can keep the upstream default in the non-first-pass path.

There was a bug in the imported algorithm that masked passes within 0.5 orbital periods of the current time. The bug has been fixed.

  1. computePassesSwath imported from upstream but appears unused in this PR. Drop dead code until needed.

removed unused computePassesSwath() from imported code orbit.js

  1. package.json adds dayjs....

duplicate

  1. lastElevation is read but reassignment after loop entry is unused in the branch where ongoingPass is true (just noting for future cleanup).

has been cleaned up

  • Modal width: 50vw will be unusable on mobile — suggest min-width + max-width responsive handling. Checklist has "Responsive at different screen sizes" unchecked.

modal min/max height and width set as follows,

        min-width: 50vw;
        max-width: 95vw;
        min-height: 25vh;
        max-height: 90vh;
  • Closing on Enter is surprising; Escape is standard. Suggest dropping Enter.

Keyboard 'Enter' key removed as option to exit modal.

… 5 degrees. Set default Boulder CO altitude 1630m.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants