Skip to content

perf(dashboard): bundle menor, corrige bugs e restringe CSP#15

Merged
oliveirara merged 8 commits into
mainfrom
feat/update-dashboard
Apr 27, 2026
Merged

perf(dashboard): bundle menor, corrige bugs e restringe CSP#15
oliveirara merged 8 commits into
mainfrom
feat/update-dashboard

Conversation

@oliveirara
Copy link
Copy Markdown
Contributor

@oliveirara oliveirara commented Apr 27, 2026

Resumo

  • Reescreve o tema para tirar backdrop-filter (principal causa de jank de scroll), trocando por gradientes opacos com a mesma estética dark/aqua.
  • Remove @mui/x-data-grid (~108 KB gz) e recoil (não usado): bundle inicial servido cai de ~285 KB gz para ~162 KB gz.
  • Substitui o DataGrid em ObjectsTable por VirtualizedList e em DataTables por Table do @mui/material (já no bundle).
  • SkyMap em dois canvases (estático + overlay animado) e worker carregado via ?worker import.
  • Indexa database/consolidated/cutouts por JNAME → seleção O(1).
  • Restringe CSP e move endpoint do MinIO para VITE_MINIO_ENDPOINT.

Bugs corrigidos

  • Imagens quebradas ao reabrir aba Cutouts: a blob URL era revogada no unmount enquanto o react-query mantinha a string em cache. Removidos o revokeBlobUrl no unmount e o invalidateQueries no mount do CutoutGrid (que anulava o cache a cada navegação).
  • Domain de filtros incorreto em datasets > 10k: amostragem step=10 perdia mínimos/máximos reais — substituído por uma única passada em loop.
  • Stack overflow potencial em Math.min(...arr) para arrays grandes — trocado por loop.
  • Debounce duplo de busca (FiltersDrawer 300ms + App.tsx 300ms = 600ms): unificado em 250ms apenas no App.
  • Worker fallback de 1s em SkyMap rodava a projeção em duplicidade na main thread — aumentado para 15s.
  • Endpoint zrok hardcoded em api.ts ignorando VITE_MINIO_ENDPOINT.
  • Closure com state velho no Gallery (componente removido — era dead code).

Segurança

  • CSP: removidos http:/ws:/wss:; adicionados base-uri 'self', form-action 'self', frame-ancestors 'none'.
  • Endpoint MinIO injetado via VITE_MINIO_ENDPOINT no build; <img> com referrerPolicy="no-referrer".

CI

  • .github/workflows/deploy.yml passa VITE_MINIO_ENDPOINT (secret) no step de build.
  • Antes do merge: cadastrar o secret em Settings → Secrets and variables → Actions. Sem ele os cutouts vão 404 em produção. Lembrando que VITE_* é inlined no bundle (visível no JS público).

Bundle (gzip)

chunk antes depois
mui-core 108.81 KB 94.88 KB
mui-datagrid 108.18 KB
recoil ~25 KB
módulos transformados 1498 983

Limpeza

Arquivos removidos por estarem mortos: Gallery.tsx, PerformanceMonitor.tsx, utils/columnWidth.ts.

Test plan

  • npm run build (0 erros)
  • npm run lint (0 erros; só warnings de any pré-existentes)
  • npm run preview com BASE_PATH=/slcomp/ e VITE_MINIO_ENDPOINT setado
  • Cadastrar VITE_MINIO_ENDPOINT no GitHub antes do merge
  • Rodar workflow via workflow_dispatch e validar o deploy
  • No site publicado:
    • Carrega dados e aplica filtros sem lag
    • Selecionar objeto: SkyMap anima a estrela, lista rola até a linha
    • Aba Cutouts carrega imagens
    • Sair e voltar para Cutouts: imagens reaparecem (regressão do blob)
    • Sliders cobrem o range real (regressão do domain)
    • Console sem CSP violations

Summary by CodeRabbit

  • New Features

    • Improved sky map visualization with smoother animations and optimized rendering.
  • Bug Fixes

    • Strengthened security policies for safer content delivery.
  • Improvements

    • Simplified table displays with custom rendering and virtualization for better performance.
    • Replaced translucent design with solid styling for improved clarity.
    • Streamlined image handling with environment-based configuration.
    • Removed Gallery component for a more focused interface.
  • Dependencies

    • Removed unused packages to reduce bundle size.

- removed @mui/x-data-grid and recoil from dependencies
- added package-lock.json for dependency management
- refine content security policy for improved security
- remove unused dependencies from Vite configuration
- deleted Gallery and PerformanceMonitor components to streamline the codebase
- removed unused columnWidth utility file
- set BASE_PATH and VITE_MINIO_ENDPOINT in build step for better configuration
@oliveirara oliveirara requested a review from Copilot April 27, 2026 02:35
@oliveirara oliveirara self-assigned this Apr 27, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 27, 2026

Warning

Rate limit exceeded

@oliveirara has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 11 minutes and 54 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ 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.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bf938741-aded-409e-9fc4-590497b7a7e0

📥 Commits

Reviewing files that changed from the base of the PR and between 7ce2152 and 8d7efdb.

📒 Files selected for processing (11)
  • dashboard/index.html
  • dashboard/prepare_data.py
  • dashboard/src/App.tsx
  • dashboard/src/api.ts
  • dashboard/src/components/CutoutGrid.tsx
  • dashboard/src/components/DataTables.tsx
  • dashboard/src/components/FiltersDrawer.tsx
  • dashboard/src/components/SkyMap.tsx
  • dashboard/src/components/VirtualizedList.tsx
  • dashboard/src/workers/skyProjectionWorker.ts
  • dashboard/tsconfig.json
📝 Walkthrough

Walkthrough

This PR refactors the dashboard by removing @mui/x-data-grid and recoil dependencies, replacing DataGrid components with custom MUI Table and VirtualizedList implementations, eliminating the Gallery and PerformanceMonitor components, optimizing data retrieval with Map-based caching in App.tsx, and transitioning the theme from translucent "liquid glass" to solid styling. Content Security Policy is tightened, and worker-based rendering in SkyMap is restructured with a WorkerPool and two-canvas approach.

Changes

Cohort / File(s) Summary
Build & Dependency Configuration
.github/workflows/deploy.yml, dashboard/package.json, dashboard/vite.config.ts
Environment variables moved to step-level config; @mui/x-data-grid and recoil removed from dependencies and optimization bundles; vite config simplified to remove DataGrid-related chunks.
Core Data Management
dashboard/src/App.tsx, dashboard/src/api.ts, dashboard/src/workers/skyProjectionWorker.ts
App.tsx refactored with unified single-pass domain/baseObjects computation, Map-based JNAME reference lookup, and per-selection caching; api.ts removes in-memory request cache, adds MinIO environment-driven configuration, removes revokeBlobUrl export; worker improved with typed message handling and shared toNum helper.
Removed Components
dashboard/src/components/Gallery.tsx, dashboard/src/components/PerformanceMonitor.tsx
Gallery component and related async image loading workflow deleted; PerformanceMonitor component and usePerformanceStats hook deleted entirely.
Table & List Refactoring
dashboard/src/components/DataTables.tsx, dashboard/src/components/ObjectsTable.tsx, dashboard/src/components/VirtualizedList.tsx
DataTables replaces DataGrid with custom MUI Table-based renderer and internal pagination; ObjectsTable replaces DataGrid with VirtualizedList; VirtualizedList enhanced with scrollToIndex and itemKey props for improved selection navigation.
Component Simplifications
dashboard/src/components/CutoutGrid.tsx, dashboard/src/components/FiltersDrawer.tsx, dashboard/src/components/SkyMap.tsx
CutoutGrid removes query invalidation and blob revocation cleanup; FiltersDrawer removes debounced search draft and simplifies styling; SkyMap refactored with WorkerPool, two-canvas rendering (base + overlay), and RAF-based animation.
Styling & Security
dashboard/index.html, dashboard/src/theme.ts
CSP meta tag tightened to restrict HTTP, add base-uri, form-action, frame-ancestors directives; theme shifts from translucent backdrop-filter aesthetic to solid gradients and opaque backgrounds, removing DataGrid-specific overrides.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

  • Add dashboard for explore data #5: Directly refactors many of the same dashboard modules (App.tsx, api.ts, CutoutGrid, DataTables, FiltersDrawer, Gallery, ObjectsTable, SkyMap, VirtualizedList, vite.config.ts) and the deploy workflow.
  • chore: update dependencies and configurations #6: Modifies the same dashboard files (dashboard/src/api.ts endpoint handling and dashboard/index.html CSP settings) with potentially conflicting changes to MinIO endpoint resolution and CSP configuration.

Poem

🐰 A rabbit refactors with careful delight,
Swaps grids for tables, makes solid what's bright,
Maps cache the data in fast-hopping style,
Two canvases paint the sky for a while,
The dashboard now glimmers—no glass, all compile! ⭐

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'perf(dashboard): bundle menor, corrige bugs e restringe CSP' accurately and specifically describes the three main objectives: performance optimization via smaller bundle, bug fixes, and Content Security Policy restrictions.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/update-dashboard

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.

- update assignment method to use `.at[]` for scalar access
- ensure compatibility with pandas >= 2.x to avoid errors
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR optimizes the dashboard bundle/runtime performance and tightens security defaults (CSP + configurable MinIO endpoint), while also removing unused/dead code and dependencies.

Changes:

  • Removes @mui/x-data-grid and recoil, replacing grids with lighter-weight MUI Table + a custom VirtualizedList.
  • Refactors SkyMap rendering (2-canvas layering) and moves projection work to a Vite ?worker module worker with a main-thread fallback.
  • Tightens CSP and updates deployment to inject VITE_MINIO_ENDPOINT at build time; adjusts cutout fetching/caching behavior.

Reviewed changes

Copilot reviewed 17 out of 20 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
package-lock.json Adds a root lockfile (new).
dashboard/vite.config.ts Removes DataGrid/recoil-related chunking and dep optimization.
dashboard/src/workers/skyProjectionWorker.ts Refines worker implementation and typing for sky projection.
dashboard/src/theme.ts Updates theme to remove backdrop-filter/translucency-heavy styling.
dashboard/src/components/VirtualizedList.tsx Adds scrollToIndex + stable item keys for virtualization.
dashboard/src/components/SkyMap.tsx Refactors worker usage + rendering pipeline with base/overlay canvases.
dashboard/src/components/ObjectsTable.tsx Replaces DataGrid with VirtualizedList-backed list UI.
dashboard/src/components/FiltersDrawer.tsx Removes internal debounce and simplifies drawer paper styling.
dashboard/src/components/DataTables.tsx Replaces DataGrid with MUI Table + pagination.
dashboard/src/components/CutoutGrid.tsx Removes query invalidation + blob revocation; adds referrerPolicy.
dashboard/src/api.ts Makes MinIO endpoint configurable; introduces blob URL caching policy changes.
dashboard/src/App.tsx Consolidates indexing/domain computation; unifies debounce timing; integrates new tables.
dashboard/package.json Drops @mui/x-data-grid and recoil dependencies.
dashboard/package-lock.json Removes DataGrid/recoil transitive deps from lockfile.
dashboard/index.html Tightens CSP directives (removes http/ws/wss allowances; adds base-uri/frame-ancestors etc.).
.github/workflows/deploy.yml Passes VITE_MINIO_ENDPOINT into the build environment.
dashboard/src/components/PerformanceMonitor.tsx Removes dead code.
dashboard/src/components/Gallery.tsx Removes dead code.
dashboard/src/utils/columnWidth.ts Removes dead code.
Files not reviewed (1)
  • dashboard/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread dashboard/src/components/CutoutGrid.tsx Outdated
Comment thread dashboard/src/api.ts Outdated
Comment thread dashboard/src/components/CutoutGrid.tsx Outdated
Comment thread dashboard/src/components/SkyMap.tsx
Comment thread dashboard/src/App.tsx Outdated
Comment thread dashboard/src/components/SkyMap.tsx Outdated
Comment thread dashboard/src/components/VirtualizedList.tsx Outdated
Comment thread dashboard/src/components/SkyMap.tsx Outdated
Comment thread dashboard/src/api.ts Outdated
Comment thread dashboard/src/components/SkyMap.tsx Outdated
Copy link
Copy Markdown
Contributor

@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: 5

🧹 Nitpick comments (5)
dashboard/src/theme.ts (1)

42-60: LGTM — note minor first-paint mismatch with index.html inline style.

dashboard/index.html (lines 12–16) still applies a radial gradient (radial-gradient(circle at 20% 20%, #13242d, #091015, #060b0f)) to body, while this MuiCssBaseline override replaces it with a different linear gradient on #03060a. There's a brief perceptible color/shape change on first paint while the JS bundle hydrates and CssBaseline takes over.

Optional: align the inline <style> in index.html with this theme's gradient to avoid the flash, or drop the inline gradient and keep only background-color: #03060a`` until CssBaseline runs.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@dashboard/src/theme.ts` around lines 42 - 60, The inline style in index.html
is causing a first-paint flash because it uses a different radial gradient than
the theme's MuiCssBaseline override; update index.html's inline <style> (body
rule) to either match the MuiCssBaseline backgroundImage
('linear-gradient(135deg, `#04080d` 0%, `#061018` 50%, `#04080d` 100%)') or remove the
inline gradient entirely and leave only background-color: `#03060a` so the initial
paint matches the theme provided by MuiCssBaseline and avoids a perceptible
color/shape change during hydration.
.github/workflows/deploy.yml (1)

58-64: Fail-fast on missing VITE_MINIO_ENDPOINT to avoid a silently-broken deploy.

If the GH secret is not set (the PR notes this is required pre-merge), ${{ secrets.VITE_MINIO_ENDPOINT }} resolves to an empty string, the build still succeeds, and prod ships with cutouts pointing at the GH Pages base URL → 404 with no obvious CI signal. A one-line guard catches this at build time:

🛡️ Suggested guard
       - name: Build
         env:
           BASE_PATH: /slcomp/
           VITE_MINIO_ENDPOINT: ${{ secrets.VITE_MINIO_ENDPOINT }}
         run: |
           cd dashboard
+          if [ -z "${VITE_MINIO_ENDPOINT}" ]; then
+            echo "::error::VITE_MINIO_ENDPOINT secret is not set; cutouts will 404 in production."
+            exit 1
+          fi
+          case "${VITE_MINIO_ENDPOINT}" in
+            https://*) ;;
+            *) echo "::error::VITE_MINIO_ENDPOINT must be https:// (CSP forbids http)"; exit 1 ;;
+          esac
           npm run build

The second check pairs with the new CSP connect-src 'self' https: in dashboard/index.html so an http:// endpoint is rejected at build time rather than failing silently in the browser at runtime.

Also: please make sure the team is aware that VITE_* values are inlined into the public JS bundle — putting the endpoint behind GH Secrets does not keep it confidential, only out of source control. If hiding the endpoint matters, it must be fronted by a same-origin proxy.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/deploy.yml around lines 58 - 64, Add a fail-fast guard in
the Build step of the GitHub Actions workflow to abort the job when the required
VITE_MINIO_ENDPOINT secret is missing or insecure: in the Build step (the job
named "Build" that sets env VITE_MINIO_ENDPOINT and runs cd dashboard && npm run
build) insert a short shell check before running the build that exits non‑zero
if $VITE_MINIO_ENDPOINT is empty or begins with "http://". This ensures the
workflow fails early on a missing or non‑TLS endpoint and prevents a silently
broken prod build.
dashboard/src/workers/skyProjectionWorker.ts (1)

63-75: Optional: replace self as unknown as Worker with proper worker typing.

Inside a worker, self is DedicatedWorkerGlobalScope, not Worker. The double-cast works but obscures the type. Cleaner alternatives:

♻️ Suggested cleanup
+declare const self: DedicatedWorkerGlobalScope;
 self.onmessage = (e: MessageEvent) => {
   const { objects, requestId } = e.data as { objects: SkyObject[]; requestId: number };
   try {
     const projectedPoints = projectObjects(objects);
-    (self as unknown as Worker).postMessage({ requestId, projectedPoints, success: true });
+    self.postMessage({ requestId, projectedPoints, success: true });
   } catch (error) {
-    (self as unknown as Worker).postMessage({
+    self.postMessage({
       requestId,
       error: error instanceof Error ? error.message : 'Unknown error',
       success: false
     });
   }
 };

Or add "webworker" to the lib array in dashboard/tsconfig.json:

"lib": ["DOM", "DOM.Iterable", "ES2020", "webworker"]

The typed MessageEvent handler and toNum extraction are correct—NaN coercions are filtered at line 49 before any trig math, so untrusted input stays safe.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@dashboard/src/workers/skyProjectionWorker.ts` around lines 63 - 75, The
worker currently uses a double-cast "(self as unknown as Worker).postMessage"
which obscures proper typing; replace that with the correct
DedicatedWorkerGlobalScope typing (e.g., const workerScope = self as
DedicatedWorkerGlobalScope; use workerScope.postMessage(...) in the
self.onmessage handler) or add "webworker" to the dashboard/tsconfig.json "lib"
array so TypeScript recognizes self as a worker global; update both the success
and error postMessage calls in the onmessage handler (the block that calls
projectObjects and posts results) to use the properly typed scope instead of the
double-cast.
dashboard/src/App.tsx (1)

24-29: Optional: drop the unsafe as unknown as cast on NUMERIC_FIELDS.

NUMERIC_FIELDS is as const (readonly tuple), so the cast widens it through unknown. If FiltersDrawer's prop is widened to readonly { key: string; label: string }[] (or a generic), the cast becomes unnecessary and you keep compile-time guarantees that field keys match the domain map.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@dashboard/src/App.tsx` around lines 24 - 29, NUMERIC_FIELDS is declared with
"as const" but an unsafe "as unknown as" cast was used to satisfy FiltersDrawer;
remove that cast and instead widen the FiltersDrawer prop type to accept
readonly tuples or a ReadonlyArray of the field shape (e.g. change the prop from
mutable array type to readonly { key: string; label: string }[] or make
FiltersDrawer generic over the tuple type), then keep NUMERIC_FIELDS as "as
const" so callers retain the literal/readonly types without the unsafe cast.
dashboard/src/components/SkyMap.tsx (1)

402-462: Pan churns the interaction useEffect — listeners are torn down/re-attached every mousemove.

transform is recomputed each time pan changes (and pan changes per pointermove via setPan). Because transform is in the dep array, this effect detaches and re-adds all 7 DOM listeners on every frame of a drag. On a busy SkyMap this is measurable.

Move the click hit-test's coordinate inputs through refs so the effect can run once with a stable handler.

Sketch
+  const transformRef = useRef(transform);
+  const ptsRef = useRef(pts);
+  const zoomRef = useRef(zoom);
+  useEffect(() => { transformRef.current = transform; }, [transform]);
+  useEffect(() => { ptsRef.current = pts; }, [pts]);
+  useEffect(() => { zoomRef.current = zoom; }, [zoom]);
@@
-  useEffect(() => {
+  useEffect(() => {
     const canvas = overlayCanvasRef.current;
     if (!canvas) return;
     ...
-      const { baseScaleX, baseScaleY, centerX, centerY } = transform;
+      const { baseScaleX, baseScaleY, centerX, centerY } = transformRef.current;
+      const z = zoomRef.current;
+      const points = ptsRef.current;
       ...
-  }, [pts, transform, zoom, onSelect]);
+  }, [onSelect]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@dashboard/src/components/SkyMap.tsx` around lines 402 - 462, The effect
attaches DOM listeners on overlayCanvasRef in useEffect but includes changing
values (transform, pts, zoom, onSelect) in its dependency array so listeners are
torn down/re-attached on every pan/mousemove; fix it by stabilizing the handler
inputs via refs: create refs like ptsRef, transformRef (or separate
baseScaleXRef/baseScaleYRef/centerXRef), zoomRef and onSelectRef and update them
wherever pts/transform/zoom/onSelect change, then inside the useEffect handlers
(onClick, onWheel, onMove, etc.) read from those refs instead of closing over
the state; finally remove transform/pts/zoom/onSelect from the useEffect
dependency array so the listeners are added once for overlayCanvasRef and only
cleaned up on unmount.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@dashboard/index.html`:
- Line 8: The CSP prevents plain http: connections which breaks cutout image
fetches when MinIO is configured with http; update the deployment/docs and
runtime checks: ensure the production secret VITE_MINIO_ENDPOINT uses https://
and document the HTTPS requirement in the README/deployment guide, and/or add a
runtime validation in buildCutoutUrl (or wherever VITE_MINIO_SCHEME /
VITE_MINIO_ENDPOINT are read) to reject or warn when the scheme is http (or
automatically upgrade to https), and if http support is required, note that you
must relax the CSP meta tag (connect-src/img-src) or front MinIO with an HTTPS
reverse proxy so browsers can load images.

In `@dashboard/src/api.ts`:
- Around line 25-32: The catch currently turns any AbortError into a "Request
timeout for ${url}" message even when the abort came from elsewhere; update the
logic around the fetch timeout (the timeout callback that references timeoutId)
to set a boolean flag (e.g., timedOut) when the 30s timer fires, then in the
catch check err instanceof Error && err.name === 'AbortError' && timedOut to
throw the "Request timeout for ${url}" error; otherwise rethrow or throw a new
Error that includes the original err.message (preserve the original error
details). Ensure references: timeoutId, timedOut (new flag), AbortError checks,
and url are used to locate and apply the change.
- Around line 88-101: The fetch call that sets the custom header
skip_zrok_interstitial (and Accept: 'image/*') causes a CORS preflight in
production which prevents blobCache from being populated when MinIO's CORS
policy doesn't allow that header; update the MinIO bucket CORS to include
Access-Control-Allow-Headers: skip_zrok_interstitial, Accept and
Access-Control-Allow-Methods: GET, HEAD, OPTIONS and ensure
Access-Control-Allow-Origin matches the dashboard origin so the fetch in the
function that creates blobUrl and sets blobCache (the fetch(...) ->
response.blob() / blobCache.set(...) flow) succeeds in production.

In `@dashboard/src/components/DataTables.tsx`:
- Around line 27-31: The current useMemo for computing columns only inspects
Object.keys(rows[0]) so any keys missing from the first row are dropped; change
the logic in the useMemo (the columns constant) to compute the union of keys
across all rows (e.g., iterate rows and collect every key except 'id') and then
filter that union to remove keys where every row has an empty value via
isEmptyVal, preserving the existing filtering behavior but ensuring
heterogeneous rows contribute columns.

In `@dashboard/src/components/SkyMap.tsx`:
- Around line 80-112: The onmessage handler in the SkyMap constructor currently
ignores messages where success is false causing the pending resolve to wait for
the 15s timeout; update the handler to handle error replies by retrieving the
pending entry from this.pending (which should store both resolve and the
original objects if you choose the suggested approach), and immediately call the
resolve with projectMainThread(objects) (or reject/log the worker error) and
delete the pending entry; modify where you set this.pending in project(...) (and
the pending Map shape) so entries include the original objects (or an error
handler) and ensure SkyProjectionWorker, constructor, onmessage, project,
this.pending, this.nextId and projectMainThread are used to locate and implement
the fix.

---

Nitpick comments:
In @.github/workflows/deploy.yml:
- Around line 58-64: Add a fail-fast guard in the Build step of the GitHub
Actions workflow to abort the job when the required VITE_MINIO_ENDPOINT secret
is missing or insecure: in the Build step (the job named "Build" that sets env
VITE_MINIO_ENDPOINT and runs cd dashboard && npm run build) insert a short shell
check before running the build that exits non‑zero if $VITE_MINIO_ENDPOINT is
empty or begins with "http://". This ensures the workflow fails early on a
missing or non‑TLS endpoint and prevents a silently broken prod build.

In `@dashboard/src/App.tsx`:
- Around line 24-29: NUMERIC_FIELDS is declared with "as const" but an unsafe
"as unknown as" cast was used to satisfy FiltersDrawer; remove that cast and
instead widen the FiltersDrawer prop type to accept readonly tuples or a
ReadonlyArray of the field shape (e.g. change the prop from mutable array type
to readonly { key: string; label: string }[] or make FiltersDrawer generic over
the tuple type), then keep NUMERIC_FIELDS as "as const" so callers retain the
literal/readonly types without the unsafe cast.

In `@dashboard/src/components/SkyMap.tsx`:
- Around line 402-462: The effect attaches DOM listeners on overlayCanvasRef in
useEffect but includes changing values (transform, pts, zoom, onSelect) in its
dependency array so listeners are torn down/re-attached on every pan/mousemove;
fix it by stabilizing the handler inputs via refs: create refs like ptsRef,
transformRef (or separate baseScaleXRef/baseScaleYRef/centerXRef), zoomRef and
onSelectRef and update them wherever pts/transform/zoom/onSelect change, then
inside the useEffect handlers (onClick, onWheel, onMove, etc.) read from those
refs instead of closing over the state; finally remove
transform/pts/zoom/onSelect from the useEffect dependency array so the listeners
are added once for overlayCanvasRef and only cleaned up on unmount.

In `@dashboard/src/theme.ts`:
- Around line 42-60: The inline style in index.html is causing a first-paint
flash because it uses a different radial gradient than the theme's
MuiCssBaseline override; update index.html's inline <style> (body rule) to
either match the MuiCssBaseline backgroundImage ('linear-gradient(135deg,
`#04080d` 0%, `#061018` 50%, `#04080d` 100%)') or remove the inline gradient entirely
and leave only background-color: `#03060a` so the initial paint matches the theme
provided by MuiCssBaseline and avoids a perceptible color/shape change during
hydration.

In `@dashboard/src/workers/skyProjectionWorker.ts`:
- Around line 63-75: The worker currently uses a double-cast "(self as unknown
as Worker).postMessage" which obscures proper typing; replace that with the
correct DedicatedWorkerGlobalScope typing (e.g., const workerScope = self as
DedicatedWorkerGlobalScope; use workerScope.postMessage(...) in the
self.onmessage handler) or add "webworker" to the dashboard/tsconfig.json "lib"
array so TypeScript recognizes self as a worker global; update both the success
and error postMessage calls in the onmessage handler (the block that calls
projectObjects and posts results) to use the properly typed scope instead of the
double-cast.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 55ae10b9-e914-4d86-b725-615e3eb6e6a9

📥 Commits

Reviewing files that changed from the base of the PR and between e1439b1 and 7ce2152.

⛔ Files ignored due to path filters (2)
  • dashboard/package-lock.json is excluded by !**/package-lock.json
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (17)
  • .github/workflows/deploy.yml
  • dashboard/index.html
  • dashboard/package.json
  • dashboard/src/App.tsx
  • dashboard/src/api.ts
  • dashboard/src/components/CutoutGrid.tsx
  • dashboard/src/components/DataTables.tsx
  • dashboard/src/components/FiltersDrawer.tsx
  • dashboard/src/components/Gallery.tsx
  • dashboard/src/components/ObjectsTable.tsx
  • dashboard/src/components/PerformanceMonitor.tsx
  • dashboard/src/components/SkyMap.tsx
  • dashboard/src/components/VirtualizedList.tsx
  • dashboard/src/theme.ts
  • dashboard/src/utils/columnWidth.ts
  • dashboard/src/workers/skyProjectionWorker.ts
  • dashboard/vite.config.ts
💤 Files with no reviewable changes (2)
  • dashboard/src/components/PerformanceMonitor.tsx
  • dashboard/src/components/Gallery.tsx

Comment thread dashboard/index.html Outdated
Comment thread dashboard/src/api.ts
Comment thread dashboard/src/api.ts
Comment thread dashboard/src/components/DataTables.tsx
Comment thread dashboard/src/components/SkyMap.tsx
- SkyMap WorkerPool: handle worker error replies (success:false) by
  falling back to main-thread immediately, and clear per-request
  setTimeout on success
- SkyMap: stable interaction listeners via refs (transform/pts/zoom/
  onSelect) so they aren't reattached on every pan
- SkyMap: cache selected point via Map<jname, ProjectedPoint> so the
  overlay rAF loop is O(1) per frame instead of pts.find
- SkyMap: HMR-safe beforeunload via import.meta.hot.dispose
- DataTables: derive columns from union of keys across rows, clamp page
  on row-count shrink
- VirtualizedList: ignore scrollToIndex when >= items.length
- api.ts: timedOut flag distinguishes 30s timeout from external aborts;
  DEBUG_CUTOUTS only accepts explicit "true"/"1"
- skyProjectionWorker: proper DedicatedWorkerGlobalScope typing
  (tsconfig lib += "WebWorker")
- App.tsx: drop unsafe `as unknown as` cast on NUMERIC_FIELDS via
  `satisfies readonly NumericFilterConfig[]`
- FiltersDrawer: numericFields prop is now readonly

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 18 out of 21 changed files in this pull request and generated 6 comments.

Files not reviewed (1)
  • dashboard/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread dashboard/src/components/VirtualizedList.tsx Outdated
Comment thread dashboard/src/components/SkyMap.tsx Outdated
Comment thread dashboard/index.html Outdated
Comment thread dashboard/src/api.ts Outdated
Comment thread dashboard/src/api.ts
Comment thread dashboard/src/components/CutoutGrid.tsx Outdated
- index.html: restore ws/wss in connect-src so Vite HMR keeps working
  in dev (the meta CSP applies in both dev and prod; for stricter prod
  hardening, drop them via server headers on deploy)
- api.ts: rewrite blobCache comment to honestly describe the
  session-lifetime policy and when an LRU would be warranted
- CutoutGrid: surface broken images via <img onError> + local state.
  getCutoutObject still returns the raw URL on fetch failure (so the
  browser gets a second chance), but if <img> itself fails the card
  now shows the Error placeholder instead of a silent broken image
- VirtualizedList: explicitly setScrollTop(el.scrollTop) after a
  programmatic scroll, instead of relying on the scroll event firing
- SkyMap: stop reading isPanningRef.current from JSX (cursor stayed
  stuck at 'grabbing' since refs don't trigger re-renders). Drive
  cursor via canvas.style.cursor in onDown/onUp, and guard
  releasePointerCapture against not-captured pointers

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 18 out of 21 changed files in this pull request and generated 4 comments.

Files not reviewed (1)
  • dashboard/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread dashboard/index.html
Comment thread dashboard/src/components/SkyMap.tsx
Comment thread dashboard/src/api.ts
Comment thread .github/workflows/deploy.yml
@oliveirara oliveirara merged commit 844b4a5 into main Apr 27, 2026
7 checks passed
@oliveirara oliveirara deleted the feat/update-dashboard branch April 27, 2026 03:31
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