Skip to content

Conversation

haslinghuis
Copy link
Member

@haslinghuis haslinghuis commented Sep 22, 2025

Summary by CodeRabbit

  • Refactor
    • Standardized numeric and character-input handling across keyboard, zoom, smoothing, expo, grid, and slider controls for more consistent, reliable behavior.
    • Replaced environment-specific global references with a cross-platform global exposure and added a compatibility shim that reattaches to the window when present.

@haslinghuis haslinghuis added this to the 4.0.0 milestone Sep 22, 2025
@haslinghuis haslinghuis self-assigned this Sep 22, 2025
Copy link

coderabbitai bot commented Sep 22, 2025

Warning

Rate limit exceeded

@haslinghuis has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 17 minutes and 45 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 3d57103 and 965efb7.

📒 Files selected for processing (1)
  • src/main.js (28 hunks)

Walkthrough

Refactors numeric parsing and character-code usage to explicit Number.* and .codePointAt, replaces window references with globalThis (including public exposure), and tightens several null/undefined checks and launchQueue detection in event handlers and UI logic.

Changes

Cohort / File(s) Change summary
Parsing & character-code normalization
src/main.js
Replaced parseInt/parseFloat with Number.parseInt/Number.parseFloat; replaced charCodeAt with codePointAt; updated slider, keyboard shortcut, zoom, smoothing, expo, and grid handlers to use explicit numeric parsing.
Global object & public exposure
src/main.js
Replaced window references with globalThis across drag/drop handlers, launchQueue checks, event hookups, and global API exposure; changed window.blackboxLogViewerglobalThis.blackboxLogViewer while retaining a window fallback for compatibility.
Guards and conditional tightening
src/main.js
Made null/undefined checks more explicit for bookmarks, indices, UI visibility, and launchQueue presence; adjusted related conditionals in event handlers and callbacks.

Sequence Diagram(s)

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning No pull request description was provided and the repository's template (which outlines required reviewer guidance, rationale, and CI/testing notes) was not completed, so reviewers lack the context needed to assess scope, testing, and intent. Because the description is essentially missing and does not follow the required template, this check fails. Please populate the PR description following the repository template: include a concise summary of what changed and why, list high-level file/behavioral impacts, state CI/test results or how changes were validated, mention any linked issues (e.g., "Fixes #"), and remove the placeholder template text so reviewers can evaluate the change.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The title "Code improvements" is on-topic because the changeset is a general refactor that modernizes parsing calls and replaces window references with globalThis, but it is overly generic and does not call out the primary changes (globalThis exposure and standardizing Number.parse usage) that would help reviewers or changelogs; it is concise but lacks specificity for a teammate scanning history. Because it refers to a real aspect of the change but is too broad, it meets the repository's "partially related" criterion and is acceptable as a pass.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/main.js (2)

2015-2024: Critical typo: gconfigField → configField causes ReferenceError in Expo adjust.

This throws on Alt+wheel “field-quick-adjust”.

-          changedValue += `${gconfigField.friendlyName} ${(
+          changedValue += `${configField.friendlyName} ${(
             configField.curve.power * 100
           ).toFixed(2)}%\n`;

2341-2351: Bookmark visibility/count logic treats “undefined” as a bookmark.

Use nullish checks instead of strict null:

-                      bookmarkTimes[e.which - 48] === null ? "hidden" : "visible"
+                      bookmarkTimes[e.which - 48] == null ? "hidden" : "visible"

-                    for (let i = 0; i <= 9; i++) {
-                      countBookmarks += bookmarkTimes[i] === null ? 0 : 1;
-                    }
+                    for (let i = 0; i <= 9; i++) {
+                      countBookmarks += bookmarkTimes[i] == null ? 0 : 1;
+                    }
🧹 Nitpick comments (3)
src/main.js (3)

1713-1721: Avoid brittle bookmark index extraction from className; loop also skips 9.

  • className.slice(-1) breaks when other classes are present or for multi‑digit suffixes.
  • The loop at Line 1713 excludes bookmark 9.

Apply:

- for (let i = 1; i < 9; i++) {
+ for (let i = 1; i <= 9; i++) {

-   bookmarkTimes[Number.parseInt(this.className.slice(-1))]
+   bookmarkTimes[
+     Number.parseInt(
+       this.className.match(/\bbookmark-(\d+)\b/)[1],
+       10
+     )
+   ]

1841-1847: Standardize radix and avoid repeated parses of indices.

Several Number.parseInt calls omit radix and repeat parsing. Parse once with radix 10.

Example (apply pattern to similar spots shown in ranges):

- for (const configField of graphConfig[Number.parseInt(graph)].fields) {
+ const gi = Number.parseInt(graph, 10);
+ for (const configField of graphConfig[gi].fields) {

- if (graphConfig[Number.parseInt(graph)].fields[Number.parseInt(field)].default == null) {
+ const fi = Number.parseInt(field, 10);
+ if (graphConfig[gi].fields[fi].default == null) {

Benefits: removes legacy-octal ambiguity and minor perf churn.

Also applies to: 1852-1861, 1878-1884, 1889-1897, 1921-1931, 1936-1951, 1972-1977, 1981-1991, 2015-2016, 2029-2043


2201-2296: Keyboard handling via codePointAt is fine; consider modernizing later.

Works equivalently to legacy keyCodes for ASCII. Optional follow‑up: migrate to event.key for readability and to avoid deprecated e.which.

Also applies to: 2362-2381, 2383-2416, 2418-2427, 2431-2433, 2435-2449

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2fea4f1 and 59a8c5a.

📒 Files selected for processing (1)
  • src/main.js (31 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/main.js (4)
src/graph_config_dialog.js (1)
  • graph (606-611)
src/graph_legend.js (2)
  • field (218-218)
  • i (216-216)
src/grapher.js (1)
  • field (1103-1103)
src/tools.js (5)
  • constrain (290-292)
  • i (27-27)
  • i (114-114)
  • i (138-138)
  • i (148-148)
🔇 Additional comments (4)
src/main.js (4)

441-441: LGTM: explicit radix 10 on log index parse.


2114-2121: LGTM: zoom step math with Alt/Shift is clear and consistent.

Also applies to: 2437-2445


2476-2526: LGTM: slider format/from and Number.parseFloat usage.


2537-2556: globalThis adoption — repo already uses globalThis; confirm runtime support

  • Findings: public API assigned to globalThis.blackboxLogViewer (src/main.js:2608); no occurrences of window.blackboxLogViewer. Drag/drop handlers set on globalThis at src/main.js:2537–2546; no other .ondragover/.ondrop or addEventListener('dragover'|'drop') found.
  • Other globalThis usages: src/graph_map.js:243, src/vendor.js:9, src/main.js (40, 1660, 1662, 1668), src/sticks.js:44, src/jquery.js:11,13, src/flightlog_parser.js:15–19.
  • Action: verify your supported browsers/Electron/Chromium/Node targets guarantee globalThis; if not, add a small fallback/polyfill or expose window.blackboxLogViewer alongside globalThis.blackboxLogViewer.

coderabbitai[bot]
coderabbitai bot previously approved these changes Sep 22, 2025
coderabbitai[bot]
coderabbitai bot previously approved these changes Sep 22, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/main.js (2)

39-41: Fix: bare userSettings will throw in module scope — create a binding and keep it in sync with global.

This file runs as an ES module; globalThis.userSettings = null doesn’t create a local identifier. All unqualified userSettings reads/writes below will hit a ReferenceError. Introduce a local let and sync it in the dialog callbacks.

-// TODO: this is a hack, once we move to web fix this
-globalThis.userSettings = null;
+// TODO: this is a hack, once we move to web fix this
+let userSettings = null;
+globalThis.userSettings = null;
-          prefs.get("userSettings", function (item) {
+          prefs.get("userSettings", function (item) {
             if (item) {
-              globalThis.userSettings = $.extend({}, defaultSettings, item);
+              globalThis.userSettings = $.extend({}, defaultSettings, item);
+              userSettings = globalThis.userSettings;
             } else {
-              globalThis.userSettings = defaultSettings;
+              globalThis.userSettings = defaultSettings;
+              userSettings = defaultSettings;
             }
           });
-          // onSave
-          globalThis.userSettings = newSettings;
+          // onSave
+          globalThis.userSettings = newSettings;
+          userSettings = newSettings;

Also applies to: 1659-1664, 1666-1672


2533-2543: Bug: launchQueue should be accessed via globalThis.launchQueue (ESM scoping).

Bare launchQueue isn’t a binding in modules even if present on the global object. Use the qualified reference.

-    if ("launchQueue" in globalThis) {
-      launchQueue.setConsumer(async (launchParams) => {
+    if ("launchQueue" in globalThis) {
+      globalThis.launchQueue.setConsumer(async (launchParams) => {
         console.log("Opening files by extension in the desktop:", launchParams);
         const files = [];
         for (const fileHandler of launchParams.files) {
           console.log("launchQueue file", fileHandler);
           files.push(await fileHandler.getFile());
         }
         loadFiles(files);
       });
     }
🧹 Nitpick comments (5)
src/main.js (5)

2521-2531: Harden drag-and-drop: guard for missing items and directory drops.

e.dataTransfer.items[0] or webkitGetAsEntry() may be absent; fallback to files improves cross‑browser behavior.

-    globalThis.ondrop = function (e) {
+    globalThis.ondrop = function (e) {
       e.preventDefault();
-
-      const item = e.dataTransfer.items[0];
-      const entry = item.webkitGetAsEntry();
-      if (entry.isFile) {
-        const file = e.dataTransfer.files[0];
-        loadFiles([file]);
-      }
+      const dt = e.dataTransfer;
+      if (dt.items && dt.items.length) {
+        const item = dt.items[0];
+        const entry = item.webkitGetAsEntry && item.webkitGetAsEntry();
+        if (!entry || entry.isFile) {
+          const file = dt.files[0];
+          if (file) loadFiles([file]);
+        }
+      } else if (dt.files && dt.files.length) {
+        loadFiles(Array.from(dt.files));
+      }
       return false;
     };

1714-1720: Make radix explicit when parsing bookmark index.

Be explicit to avoid edge cases; also avoid parsing from class name when a data‑ attribute would be cleaner.

-        setCurrentBlackboxTime(
-          bookmarkTimes[Number.parseInt(this.className.slice(-1))]
-        );
+        setCurrentBlackboxTime(
+          bookmarkTimes[Number.parseInt(this.className.slice(-1), 10)]
+        );

1840-1849: Use plain object for default instead of array-like.

default = [] is misleading; use {} for shape fields.

-          if (configField.default == null) {
-            configField.default = [];
+          if (configField.default == null) {
+            configField.default = {};
             configField.default.smoothing = configField.smoothing;
             configField.default.power = configField.curve.power;
           }
-        if (graphConfig[gi].fields[fi].default == null) {
-          graphConfig[gi].fields[fi].default = [];
+        if (graphConfig[gi].fields[fi].default == null) {
+          graphConfig[gi].fields[fi].default = {};
           graphConfig[gi].fields[fi].default.smoothing = graphConfig[gi].fields[fi].smoothing;
           graphConfig[gi].fields[fi].default.power = graphConfig[gi].fields[fi].curve.power;
           return "<h4>Stored defaults for single pen</h4>";
         }

Also applies to: 1851-1858


1969-1976: Consistency: parse field index before array access.

You parse graph but not field here. While "2" works, parsing improves clarity and avoids accidental property access.

-        const gi = Number.parseInt(graph, 10);
-        // change single pen
-        graphConfig[gi].fields[field].curve.MinMax.min *= delta ? zoomScaleOut : zoomScaleIn;
-        graphConfig[gi].fields[field].curve.MinMax.max *= delta ? zoomScaleOut : zoomScaleIn;
+        const gi = Number.parseInt(graph, 10);
+        const fi = Number.parseInt(field, 10);
+        // change single pen
+        graphConfig[gi].fields[fi].curve.MinMax.min *= delta ? zoomScaleOut : zoomScaleIn;
+        graphConfig[gi].fields[fi].curve.MinMax.max *= delta ? zoomScaleOut : zoomScaleIn;
         changedValue += delta ? "Zoom out:\n" : "Zoom in:\n";
-        changedValue += `${graphConfig[gi].fields[field].friendlyName}\n`;
+        changedValue += `${graphConfig[gi].fields[fi].friendlyName}\n`;

2163-2274: Keyboard handling changes look good; consider e.key for readability.

The switch to .codePointAt(0) aligns with legacy which codes. Optionally migrate to e.key/e.code for layout‑aware handling and to avoid deprecated which.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ecdaec7 and b4a17be.

📒 Files selected for processing (1)
  • src/main.js (28 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/main.js (4)
src/graph_config_dialog.js (1)
  • graph (606-611)
src/graph_legend.js (2)
  • field (218-218)
  • i (216-216)
src/grapher.js (1)
  • field (1103-1103)
src/tools.js (5)
  • constrain (290-292)
  • i (27-27)
  • i (114-114)
  • i (138-138)
  • i (148-148)
🔇 Additional comments (3)
src/main.js (3)

2453-2476: Slider format/parsing changes LGTM.

Using Number.parseFloat in format.from and on “slide” keeps values numeric even with “%” suffixes.

Also applies to: 2496-2499


441-448: Select log index: good use of Number.parseInt(..., 10).


2513-2520: Drag-over handler: good move to globalThis.

Prevents accidental page navigation on drops. Nice.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main.js (1)

2533-2543: Bug: launchQueue referenced as an undeclared identifier in modules. Use globalThis.launchQueue.

In ESM/strict mode, checking "launchQueue" in globalThis then calling launchQueue.setConsumer(...) throws ReferenceError. Access via globalThis.

Apply:

-    if ("launchQueue" in globalThis) {
-      launchQueue.setConsumer(async (launchParams) => {
+    if ("launchQueue" in globalThis && globalThis.launchQueue) {
+      globalThis.launchQueue.setConsumer(async (launchParams) => {
         console.log("Opening files by extension in the desktop:", launchParams);
         const files = [];
         for (const fileHandler of launchParams.files) {
           console.log("launchQueue file", fileHandler);
           files.push(await fileHandler.getFile());
         }
         loadFiles(files);
       });
     }
🧹 Nitpick comments (5)
src/main.js (5)

1713-1721: Bookmark index parsing: add radix and consider robust index extraction.

Current code slices the last class char; safer to parse data-* or the trailing digits and always use radix 10.

Apply this diff to add an explicit radix now; consider moving to a data attribute in a follow-up:

-          bookmarkTimes[Number.parseInt(this.className.slice(-1))]
+          bookmarkTimes[Number.parseInt(this.className.slice(-1), 10)]

Also verify handlers exist for 1–9 (the loop uses i < 9, so 9 may be missing).


1958-1966: Zoom adjustments: normalize field index for clarity.

Array access with a string key works, but parsing to a number improves readability and prevents accidental property access.

Apply:

       if (graph != null && field != null) {
-        const gi = Number.parseInt(graph, 10);
-        // change single pen
-        graphConfig[gi].fields[field].curve.MinMax.min *= delta ? zoomScaleOut : zoomScaleIn;
-        graphConfig[gi].fields[field].curve.MinMax.max *= delta ? zoomScaleOut : zoomScaleIn;
+        const gi = Number.parseInt(graph, 10);
+        const fi = Number.parseInt(field, 10);
+        // change single pen
+        graphConfig[gi].fields[fi].curve.MinMax.min *= delta ? zoomScaleOut : zoomScaleIn;
+        graphConfig[gi].fields[fi].curve.MinMax.max *= delta ? zoomScaleOut : zoomScaleIn;
         changedValue += delta ? "Zoom out:\n" : "Zoom in:\n";
-        changedValue += `${graphConfig[gi].fields[field].friendlyName}\n`;
+        changedValue += `${graphConfig[gi].fields[fi].friendlyName}\n`;
         return changedValue;
       }

Also applies to: 1970-1975


2180-2201: Keyboard handling: prefer e.key over numeric codes.

Using e.key (e.g., 'i','o','m',' ') improves readability and IME/layout robustness; no behavior change required.

Also applies to: 2216-2261, 2265-2274, 2338-2343, 2359-2367, 2381-2387, 2393-2399, 2407-2409


2513-2519: globalThis.ondragover is okay; consider addEventListener for composability.

Direct assignment can be clobbered by other scripts; addEventListener is safer. Optional.


2521-2531: Drag-and-drop: guard empty items and fall back to files.

Accessing items[0] can throw; also handle directories gracefully.

Apply:

-    globalThis.ondrop = function (e) {
+    globalThis.ondrop = function (e) {
       e.preventDefault();
-
-      const item = e.dataTransfer.items[0];
-      const entry = item.webkitGetAsEntry();
-      if (entry.isFile) {
-        const file = e.dataTransfer.files[0];
-        loadFiles([file]);
-      }
+      const dt = e.dataTransfer;
+      const items = dt && dt.items ? Array.from(dt.items) : [];
+      if (items.length && items[0].kind === "file") {
+        const entry = items[0].webkitGetAsEntry && items[0].webkitGetAsEntry();
+        if (!entry || entry.isFile) {
+          const file = dt.files && dt.files[0];
+          if (file) loadFiles([file]);
+        }
+      } else if (dt.files && dt.files.length) {
+        loadFiles(Array.from(dt.files));
+      }
       return false;
     };
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b4a17be and 3d57103.

📒 Files selected for processing (1)
  • src/main.js (28 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/main.js (4)
src/graph_config_dialog.js (1)
  • graph (606-611)
src/graph_legend.js (2)
  • field (218-218)
  • i (216-216)
src/grapher.js (1)
  • field (1103-1103)
src/tools.js (5)
  • constrain (290-292)
  • i (27-27)
  • i (114-114)
  • i (138-138)
  • i (148-148)
🔇 Additional comments (11)
src/main.js (11)

441-441: Use of Number.parseInt with radix is correct.

Good defensive parsing on the log index.


1564-1569: Switch to Number.parseFloat is fine here.

Maintains behavior and avoids global parseFloat.


1839-1849: Indices parsed with radix 10 — good.

Consistent integer parsing and defaults snapshotting look correct.

Also applies to: 1851-1858


1874-1883: Restore defaults path looks correct.

Radix usage and assignments are sound.

Also applies to: 1885-1894


1915-1926: Smoothing adjustments: solid bounds handling.

Use of constrain and explicit radix is good; message formatting is clear.

Also applies to: 1929-1939


1997-2007: Expo adjustments: consistent and bounded — looks good.

Radix specified; range constraints applied.

Also applies to: 2011-2021


2091-2091: Zoom step math remains correct.

Combining shift/alt modifiers with additive deltas is preserved.

Also applies to: 2098-2098, 2413-2413, 2421-2421


2457-2458: Slider format.from using Number.parseFloat is correct.

Works with strings like "100%".


2475-2476: Playback slider parsing is fine.

No regressions expected.


2497-2498: Zoom slider parsing is fine.

No regressions expected.


2584-2587: Backward-compat global alias retained — thank you.

Keeping window.blackboxLogViewer avoids breaking external consumers.

Copy link

Copy link

Preview URL: https://pr857.betaflight-blackbox.pages.dev

Copy link
Member

@nerdCopter nerdCopter left a comment

Choose a reason for hiding this comment

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

  • only briefly tested. issues with semver YYYY.MM as expected.

@haslinghuis haslinghuis merged commit 6653d1c into betaflight:master Sep 24, 2025
5 checks passed
@haslinghuis haslinghuis deleted the code-improvements branch September 24, 2025 14:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants