Conversation
There was a problem hiding this comment.
Pull Request Overview
This PR refactors the HICBrowser "God Object" by extracting distinct responsibilities into dedicated coordinator/manager classes following the Single Responsibility Principle. The refactoring introduces StateManager, NotificationCoordinator, InteractionHandler, DataLoader, and RenderCoordinator to separate state management, UI notifications, user interactions, data loading, and rendering concerns.
Key Changes
- Extracted state management into StateManager class for centralized dataset and state handling
- Created NotificationCoordinator to handle all UI component notifications
- Introduced InteractionHandler for user interaction methods (goto, zoom, pan)
- Added DataLoader to manage Hi-C file, track, and normalization data loading
- Implemented RenderCoordinator to handle rendering coordination and queuing
Reviewed Changes
Copilot reviewed 36 out of 36 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| js/hicBrowser.js | Refactored to delegate responsibilities to new coordinator classes while maintaining backward compatibility |
| js/stateManager.js | New class managing active dataset, state transitions, and cross-browser synchronization |
| js/notificationCoordinator.js | New class coordinating UI component updates when browser state changes |
| js/interactionHandler.js | New class handling navigation, zoom, and pan operations |
| js/dataLoader.js | New class managing data loading operations for Hi-C files, tracks, and normalizations |
| js/renderCoordinator.js | New class coordinating rendering with queuing logic for rapid calls |
| js/hicState.js | Added helper methods for state validation, pixel size adjustment, and update finalization |
| js/urlUtils.js | Added session loading from File objects and file paths with URL shortcut expansion |
| js/session.js | Added URL shortcut expansion for backward compatibility |
| test/testSession.js | New test file for session loading functionality |
| vite.config.js | Added plugins to suppress source map warnings for third-party dependencies |
| various widget files | Added helper methods to encapsulate DOM manipulation |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| } | ||
|
|
||
| juicebox.init(document.getElementById("app-container"), config_deep_map) | ||
| juicebox.init(document.getElementById("app-container"), config) |
There was a problem hiding this comment.
Variable config_deep_map is changed to config, but config is not defined in this file. This will cause a ReferenceError at runtime. Either define config or revert to config_deep_map.
There was a problem hiding this comment.
@copilot open a new pull request to apply changes based on this feedback
| } catch (error) { | ||
| this.browser.contactMapLabel.textContent = ""; | ||
| this.browser.contactMapLabel.title = ""; | ||
| config.name = name; |
There was a problem hiding this comment.
Variable name is used before it's defined. The line config.name = name references name from line 84, but this code is in the catch block after the try block where name was defined. If an error occurs before line 84, name will be undefined, causing this assignment to fail silently or set config.name to undefined.
| customLogger: { | ||
| warn(msg, options) { | ||
| // Filter out source map warnings for igv dependencies | ||
| const message = typeof msg === 'string' ? msg : String(msg); | ||
| if (message.includes('igv-ui.css.map') || | ||
| message.includes('Failed to load source map') || | ||
| (message.includes('ENOENT') && message.includes('igv'))) { | ||
| return; // Suppress these warnings | ||
| } | ||
| // Use default warning logger for other messages | ||
| console.warn(msg, options); | ||
| }, | ||
| error(msg, options) { | ||
| // Filter out source map errors for igv dependencies | ||
| const message = typeof msg === 'string' ? msg : String(msg); | ||
| if (message.includes('igv-ui.css.map') || | ||
| message.includes('Failed to load source map') || | ||
| (message.includes('ENOENT') && message.includes('igv'))) { | ||
| return; // Suppress these errors | ||
| } | ||
| // Use default error logger for other messages | ||
| console.error(msg, options); |
There was a problem hiding this comment.
The custom logger's warn and error methods call console.warn(msg, options) and console.error(msg, options). However, the standard console methods don't accept an options parameter in this way. This may cause issues or unexpected behavior. Consider spreading the arguments or checking if options is defined before passing it.
| "height": 1000, | ||
| "url": "https://www.encodeproject.org/files/ENCFF799QGA/@@download/ENCFF799QGA.hic", | ||
| "name": "in-situ agar GM12878 MboI experiment", | ||
| // "name": "in-situ agar GM12878 MboI experiment", |
There was a problem hiding this comment.
Property "name" is commented out but should either be removed entirely or have an explanation for why it's commented out. Leaving commented-out code reduces maintainability.
| // "name": "in-situ agar GM12878 MboI experiment", |
| for (i = 0; i < resolutions.length; i++) { | ||
| if (this.browser.state.zoom === resolutions[i].index) break; | ||
| } | ||
| if (i !== undefined) { |
There was a problem hiding this comment.
This guard always evaluates to true.
| if (i !== undefined) { | |
| if (i < resolutions.length) { |
| * @param {boolean} eventData.dragging - Whether currently dragging | ||
| */ | ||
| notifyLocusChange(eventData) { | ||
| const { state, resolutionChanged, chrChanged, dragging } = eventData; |
There was a problem hiding this comment.
Unused variable dragging.
| const { state, resolutionChanged, chrChanged, dragging } = eventData; | |
| const { state, resolutionChanged, chrChanged } = eventData; |
| this.updating = false; | ||
| if (this.pending.size > 0) { | ||
| const queued = []; | ||
| for (let [k, v] of this.pending) { |
There was a problem hiding this comment.
Unused variable k.
| for (let [k, v] of this.pending) { | |
| for (let v of this.pending.values()) { |
|
|
||
| import { describe, test, expect } from 'vitest'; | ||
| import { extractConfig } from "../js/urlUtils.js"; | ||
| import { restoreSession } from "../js/session.js"; |
There was a problem hiding this comment.
Unused import restoreSession.
No description provided.