Julenmendieta/MILAB-6617_adaptToSingleCellVhh - #38
Conversation
There was a problem hiding this comment.
Code Review
This pull request dynamically filters single-cell chain options based on the columns present in the selected dataset, hiding the selector when only one chain is available. Feedback points out a potential runtime TypeError in model/src/index.ts due to inconsistent null-checking of spec, and a stale state issue in ui/src/app.ts when switching datasets, suggesting a watchEffect to automatically update the selected chain.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
Greptile Summary
This PR fixes a workflow crash on VHH (heavy-chain-only) single-cell IG datasets where the chain selector previously offered "Light" even when no light-chain columns existed. A new model output
availableScChainsreports which chain letters actually have V-gene columns; the UI chain selector is filtered to that set and hidden when only one chain is present.model/src/index.ts— Adds theavailableScChainsoutput, which inspectspl7.app/vdj/geneHit/VGenecolumns for the primary chain index to detect which chains have real data; returnsundefined(no filter) for bulk and non-IG datasets.ui/src/utils.ts—useScChainOptionsgains a secondavailableChainsargument and filters the receptor-derived options list, falling back to the full list while the output is still resolving (undefined).ui/src/pages/Settings.vue— The chainPlBtnGroupis now hidden whenscChainOptions?.length ≤ 1, removing the user's ability to pick an invalid chain.Confidence Score: 3/5
The chain selector is correctly hidden for VHH datasets, but the underlying scChain model field can remain stale when a user switches from a paired IG dataset to a VHH one, leaving the backend to fail with the same error the PR set out to fix.
The new availableScChains output and option-filtering logic are sound. The gap is in Settings.vue and app.ts: hiding the UI control does not reset model.data.scChain, so an existing block with Light chain (B) previously selected will still send B to the workflow after a VHH dataset is chosen.
ui/src/pages/Settings.vue and ui/src/app.ts — no auto-reset of model.data.scChain when the available chain list narrows to a single entry.
Important Files Changed
availableScChainsoutput that probes the result pool for V-gene columns per chain; logic looks correct for the IG/VHH case, and the output correctly returnsundefinedfor resolving/empty pool states which is handled upstream in the UI.useScChainOptionsto accept and filter byavailableChains; fall-through forundefined(resolving) is handled; TCR path is unaffected sinceavailableScChainsreturnsundefinedfor non-IG.scChainOptions?.length ≤ 1, but does not resetmodel.data.scChainwhen a dataset switch leaves a stale chain value that will fail the backend workflow.availableScChainstouseScChainOptionsfor label-generation use; no auto-reset logic added for thescChaindata field.Sequence Diagram
%%{init: {'theme': 'neutral'}}%% sequenceDiagram participant UI as Settings.vue participant Utils as utils.ts (useScChainOptions) participant Model as model/index.ts (availableScChains) participant Pool as ResultPool UI->>Model: reads availableScChains output Model->>Pool: getPColumnSpecByRef(datasetRef) alt spec is not SC-IG Model-->>UI: undefined (no filtering) else spec is SC-IG Model->>Pool: getAnchoredPColumns(VGene / primary index) alt pool still resolving Pool-->>Model: undefined Model-->>UI: undefined (no filtering) else columns available Pool-->>Model: [col_A, col_B, ...] Model->>Model: collect chain letters from domain Model-->>UI: ["A"] or ["A","B"] end end UI->>Utils: useScChainOptions(datasetSpec, availableScChains) Utils->>Utils: build full receptor options (IG to Heavy/Light) alt availableScChains is undefined Utils-->>UI: full options list (fallback) else availableScChains is [] Utils-->>UI: [] (hidden, nothing to pick) else availableScChains is ["A"] Utils-->>UI: "[{Heavy, A}] (hidden, only one chain)" else availableScChains is ["A","B"] Utils-->>UI: "[{Heavy,A},{Light,B}] (shown)" end UI->>UI: "v-if length > 1, show/hide PlBtnGroup" Note over UI: scChain in model.data is NOT reset when selector is hidden%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% sequenceDiagram participant UI as Settings.vue participant Utils as utils.ts (useScChainOptions) participant Model as model/index.ts (availableScChains) participant Pool as ResultPool UI->>Model: reads availableScChains output Model->>Pool: getPColumnSpecByRef(datasetRef) alt spec is not SC-IG Model-->>UI: undefined (no filtering) else spec is SC-IG Model->>Pool: getAnchoredPColumns(VGene / primary index) alt pool still resolving Pool-->>Model: undefined Model-->>UI: undefined (no filtering) else columns available Pool-->>Model: [col_A, col_B, ...] Model->>Model: collect chain letters from domain Model-->>UI: ["A"] or ["A","B"] end end UI->>Utils: useScChainOptions(datasetSpec, availableScChains) Utils->>Utils: build full receptor options (IG to Heavy/Light) alt availableScChains is undefined Utils-->>UI: full options list (fallback) else availableScChains is [] Utils-->>UI: [] (hidden, nothing to pick) else availableScChains is ["A"] Utils-->>UI: "[{Heavy, A}] (hidden, only one chain)" else availableScChains is ["A","B"] Utils-->>UI: "[{Heavy,A},{Light,B}] (shown)" end UI->>UI: "v-if length > 1, show/hide PlBtnGroup" Note over UI: scChain in model.data is NOT reset when selector is hiddenPrompt To Fix All With AI
Reviews (1): Last reviewed commit: "Changeset" | Re-trigger Greptile
Context used: