Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions js/widgets/trackSelectionListModal.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
export default function createTrackSelectionListModal({id, label = '', sections, description = '', okHandler}) {
export default function createTrackSelectionListModal({id, label = '', groups, description = '', okHandler}) {

// Flatten sections to get all tracks.
// Flatten groups to get all tracks.
const tracks = []
const trackMap = new Map()
const flattenSections = (sections) => {
sections.forEach(section => {
if (section.tracks) {
section.tracks.forEach(track => {
const flattenGroups = (groups) => {
groups.forEach(group => {
if (group.tracks) {
group.tracks.forEach(track => {
tracks.push(track)
trackMap.set(track._id, track)
})
}
if (section.children) {
flattenSections(section.children)
if (group.children) {
flattenGroups(group.children)
}
})
}
flattenSections(sections)
flattenGroups(groups)

// Generate the HTML for the modal
const renderTracks = (tracks) => {
Expand Down
32 changes: 16 additions & 16 deletions js/widgets/trackSelectionModal.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export default function createTrackSelectionModal({id, label = '', sections, description = '', okHandler}) {
export default function createTrackSelectionModal({id, label = '', groups, description = '', okHandler}) {
const html = `
<div id="${id}" class="modal fade igv-app-track-select-modal" tabindex="-1">
<div class="modal-dialog modal-lg">
Expand All @@ -9,7 +9,7 @@ export default function createTrackSelectionModal({id, label = '', sections, des
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body overflow-auto" style="max-height: 70vh;">
${renderSections(sections, 0)}
${renderGroups(groups, 0)}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-sm btn-outline-secondary" data-bs-dismiss="modal">Cancel</button>
Expand All @@ -20,28 +20,28 @@ export default function createTrackSelectionModal({id, label = '', sections, des
</div>
`

function renderSections(sections, level) {
return sections.map((section, index) => {
//console.log(`Rendering section: ${section.label}, level: ${level}`);
function renderGroups(groups, level) {
return groups.map((group, index) => {
//console.log(`Rendering group: ${group.label}, level: ${level}`);
return `
<div class="mb-3">

${level === 0 ? `
<div class="bg-light text-center py-2 d-flex justify-content-between align-items-center" role="button" data-bs-toggle="collapse" data-bs-target="#collapseSection${index}" aria-expanded="true" aria-controls="collapseSection${index}">
<span style="font-size: 1.2rem;">${section.label}</span>
<span style="font-size: 1.2rem;">${group.label}</span>
<span id="collapseIcon${index}" class="bi bi-dash"></span>
</div>` : ''}

${level === 0 ?
`<div class="collapse show mt-3" id="collapseSection${index}">` :
Comment on lines 30 to 36
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

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

[nitpick] For consistency with the refactoring from "sections" to "groups", consider renaming the HTML element IDs from collapseSection${index} to collapseGroup${index} to match the new terminology throughout the codebase.

Copilot uses AI. Check for mistakes.
`<fieldset class="border rounded-3 p-3">
<legend class="form-check-label float-none w-auto px-3" style="font-size: 1.0rem;">
${section.label}
${group.label}
</legend><div>`}
<form>
<div class="container">
<div class="row g-2">
${section.tracks ? section.tracks.map((track) => `
${group.tracks ? group.tracks.map((track) => `
<div class="col-6 col-md-4">
<div class="form-check d-flex align-items-center">
<input class="form-check-input" type="checkbox" id="${track._id}" ${track._loaded ? 'checked' : ''} ${track.disabled ? 'disabled' : ''}>
Expand All @@ -56,7 +56,7 @@ export default function createTrackSelectionModal({id, label = '', sections, des
</div>
`).join('') : ''}
</div>
${section.children ? `<div class="mt-3">${renderSections(section.children, level + 1)}</div>` : ''}
${group.children ? `<div class="mt-3">${renderGroups(group.children, level + 1)}</div>` : ''}
</div>
</form>
${level === 0 ? `</div>` : '</div></fieldset>'}
Expand Down Expand Up @@ -85,19 +85,19 @@ export default function createTrackSelectionModal({id, label = '', sections, des
})

const trackMap = new Map()
const fillTrackMap = (sections) => {
sections.forEach(section => {
if (section.tracks) {
section.tracks.forEach(track => {
const fillTrackMap = (groups) => {
groups.forEach(group => {
if (group.tracks) {
group.tracks.forEach(track => {
trackMap.set(track._id, track)
})
}
if (section.children) {
fillTrackMap(section.children)
if (group.children) {
fillTrackMap(group.children)
}
})
}
fillTrackMap(sections)
fillTrackMap(groups)


// Listen for the modal close event
Expand Down
23 changes: 13 additions & 10 deletions js/widgets/trackWidgets.js
Original file line number Diff line number Diff line change
Expand Up @@ -229,18 +229,18 @@ async function trackMenuGenomeChange(browser, genome) {
const loadedIDs = browser ? new Set(browser.findTracks(true).map(t => trackId(t))) : new Set()

// Annotate track config objects with a unique ID comprised of url + name
const annotateTracks = (section) => {
if (section.tracks) {
for (const track of section.tracks) {
const annotateTracks = (groups) => {
if (groups.tracks) {
for (const track of groups.tracks) {
track._id = trackId(track)
track._loaded = loadedIDs.has(track._id)
}
}
if (section.children) for (const child of section.children) {
if (groups.children) for (const child of groups.children) {
annotateTracks(child)
}
}
for (const group of config.sections) {
for (const group of config.groups) {
annotateTracks(group)
}

Expand Down Expand Up @@ -292,15 +292,18 @@ function prepRegistryConfig(registry) {
registry.customModalTable = customModalTable
return registry
} else {

const groups = registry.groups || [{
label: registry.label,
tracks: registry.tracks
}]

return {
type: registry.type || 'track-selection-modal',
id: `_${Math.random().toString(36).substring(2, 9)}`,
label: registry.label,
description: registry.description,
sections: [{
label: registry.label,
tracks: registry.tracks
}],
groups: groups
}
}
}
Expand All @@ -315,7 +318,7 @@ async function prepHubConfig(hubURL, genomeID) {
id: `_${Math.random().toString(36).substring(2, 9)}`,
label: `${hub.getShortLabel()}`,
description: descriptionUrl ? `<a target=_blank href="${descriptionUrl}">${hub.getLongLabel()}</a>` : '',
sections: groups
groups: groups
}
}

Expand Down
48 changes: 48 additions & 0 deletions resources/tracks/mm10_sample.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"label": "mm10 Sample Tracks",
"type": "hub",
"description": "Some sample tracks for the mm10 genome",
"groups": [
{
"label": "Genes and Gene Predictions",
"tracks": [
{
"id": "HLTOGAannotvHg38v1",
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

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

The track ID "HLTOGAannotvHg38v1" has inconsistent casing compared to the URL which contains "HLTOGAannotVsHg38v1" (note the capital "V" in "Vs"). Consider using consistent casing, such as "HLTOGAannotVsHg38v1" to match the URL filename.

Suggested change
"id": "HLTOGAannotvHg38v1",
"id": "HLTOGAannotVsHg38v1",

Copilot uses AI. Check for mistakes.
"name": "TOGA vs. hg38",
"url": "https://hgdownload.soe.ucsc.edu/gbdb/mm10/TOGAvHg38v1/HLTOGAannotVsHg38v1.bb"
},
{
"id": "crisprAllTargets",
"name": "CRISPR Targets",
"group": "genes",
"url": "https://hgdownload.soe.ucsc.edu/gbdb/mm10/crisprAll/crispr.bb",
"html": "https://crispor.gi.ucsc.edu/crispor.py?org=$D&pos=$S:$E&pam=NGG"
}
]
},
{
"label": "Regulation",
"tracks": [
{
"id": "encodeCcreCombined",
"name": "ENCODE cCREs",
"url": "https://hgdownload.soe.ucsc.edu/gbdb/mm10/encode3/ccre/encodeCcreCombined.bb",
"html": "https://screen-v2.wenglab.org/search/?q=$$&assembly=mm10"
},
{
"id": "refSeqFuncElems",
"name": "RefSeq Func Elems",
"group": "regulation",
"url": "https://hgdownload.soe.ucsc.edu/gbdb/mm10/ncbiRefSeq/refSeqFuncElems.bb"
},
{
"id": "vistaEnhancersBb",
"name": "VISTA Enhancers",
"group": "regulation",
"url": "https://hgdownload.soe.ucsc.edu/gbdb/mm10/vistaEnhancers/vistaEnhancers.bb",
"html": "https://enhancer.lbl.gov/cgi-bin/imagedb3.pl?form=presentation&show=1&organism_id=2&experiment_id=$<experimentId>"
}
]
}
]
}