d121edc0bd2809f1d6de6185a497e6a288958479
braney
  Tue May 12 09:18:29 2026 -0700
hgConvert quickLift: skip pre-lifted tracks, append-and-merge hub file, per-track remove UI, refs #37535

In hgConvert / trackHubBuild:
- Skip tracks that already came from a quickLift hub (quickLiftUrl / quickLifted setting) so they don't get re-lifted to a new destination.
- Append new track stanzas to an existing per-source hub file instead of overwriting it; new stanzas get priorities after the existing max; duplicate track names are skipped. Also avoids re-emitting a parent supertrack that's already in the file.

New public quickLiftHubRemoveTrack(cart, sourceDb, trackName) in trackHub.c rewrites the per-source hub file with the named stanza removed plus all descendant stanzas (parent reference cascade, transitive).

hgTrackUi: adds a "Remove from QuickLift" link next to "Duplicate track" for any tdb carrying a quickLiftDb setting. The link hits hgTrackUi_op=quickLiftRemove which calls quickLiftHubRemoveTrack, hides the track in the cart, and 302s to hgTracks. The op argument cart var is qlSourceDb (renamed from quickLiftSourceDb to avoid colliding with the quickLift.* prefix used elsewhere; values cloned out of the cart hash before cartRemove so the helper doesn't see freed strings).

hgTracks: adds a small "x" icon (printQuickLiftDelIcon) on tracks in a quickLift group, suppressed on the synthetic bigQuickLiftChain track. JS onQuickLiftDelIconClick fires the same hgTrackUi_op endpoint via synchronous XHR and removes every TD whose icon matches the deleted data-track, so the row goes away in both the QuickLift group and the Visible Tracks group.

hubConnect cart handling fixes shaken out by the above:
- hubConnectRemakeTrackHubVar's cart-var prefix is now "quickLift." (with the trailing dot) instead of "quickLift", so unrelated keys like qlSourceDb no longer get parsed as hubId/db and crash cart loading on every CGI. Also skips entries whose hubStatus lookup returned NULL.
- hubConnectStatusListFromCart no longer calls removeQuickListReference when the current db isn't the lift's destination. A side trip to another assembly between two lifts to the same destination was deleting the earlier attachment's cart var; just skip attaching this load and leave the cart alone so the lift survives the round trip.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

diff --git src/hg/htdocs/style/HGStyle.css src/hg/htdocs/style/HGStyle.css
index e5579e3f4a0..c3817cece6a 100644
--- src/hg/htdocs/style/HGStyle.css
+++ src/hg/htdocs/style/HGStyle.css
@@ -96,30 +96,37 @@
 
 }
 
 /* For words that exceed max-width */
 .trackLabelTdBreakAll {
     word-break: break-all;
 }
 
 
 .trackDeleteIcon {
         margin-right: 4px;
         display: inline;
         cursor: pointer;
 }
 
+.quickLiftDelIcon {
+        margin-right: 4px;
+        display: inline;
+        cursor: pointer;
+        color: #aa3333;
+}
+
 .controlButtons {
     margin-bottom: 6px;
 }
 
 .blueLink {
         color: #121E9A !important; 
         cursor: pointer;
 }
 
 span.link {
         color: #121E9A; 
         text-decoration: underline; 
         cursor: pointer
 }