Repository navigation
Choose per file column whether to add, fill or skip on metadata import - #134
Merged
Merged
Conversation
A project seeded from a template carries its metadata columns with no values, so the import has to be able to point a file column at an existing column rather than only match it by name. Every column of the file now gets its own action: become a new metadata column, fill an existing column of the project, or stay out. Name and type matches are pre-selected, so an import nobody touches behaves as it did. A second mode replaces the project's metadata wholesale, warning that blocks downstream lose the columns they were pointed at. Values are checked against the target column's type on write: numbers are stringified for String columns, strings no longer land in numeric ones. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
AStaroverov
enabled auto-merge
September 10, 2026 13:55
A global metadata column is exported with its label in the PColumn domain, so two columns sharing a label are exported as one and lose each other's values. Two paths could produce that pair: a file column whose name matches a project column it cannot fill for want of a compatible type, and two columns of one file whose headers differ only in case or padding. Column creation now settles the clash by numbering the newcomer, so neither the metadata dialog nor the samplesheet import can build a colliding pair. The dialog reports the columns it had to rename and points at filling the existing column instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Contributor
Author
The `d`-flag indices array now types every entry as possibly absent, so destructuring one without a check stopped compiling under the TypeScript that came with the dependency update. Both reads are of entries that are always there: the whole match, and a group the caller has already found in the match. Asserting them keeps the parser as it was and gets the UI package type checking again. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A non-null assertion states the expectation without checking it. Both reads of the `d`-flag positions now check and throw when what they expect is absent: the indices array itself, the entry for a capture group the caller has already found in the match, and the entry for the whole match. The parser behaves as before wherever the flag is set, which is everywhere this module builds a pattern. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
A project created from a template gets its datasets and metadata columns without any values, so after applying a template the user re-imports a metadata file. Until now the import matched file columns to project columns by name only: a column whose header differed from the project's column silently became a second, new column, and there was no way to say "this column of my file is the project's
Tissue".What changed
Every column of the file now carries its own action in the import dialog:
Columns whose name and type match an existing column are pre-set to fill it, and each project column is auto-claimed at most once, so an import nobody touches behaves exactly as before.
A mode switch above the list picks between Keep existing columns and Replace all metadata. Replace deletes every existing column and rebuilds the metadata from the file, with a warning that blocks downstream lose the columns they were pointed at and the project has to be re-checked.
Three warnings guard the mapping:
Values are now checked against the target column's type on write: numbers are stringified for String columns, strings no longer land in numeric columns. This also affects the samplesheet import, which shares the same helpers.
Notes
Filling an existing column reuses its column object rather than renaming anything, which keeps the
pl7.app/columnIddomain stable and leaves downstream block selections valid.Testing
ui/src/utils/metadata.test.tscovers the default mapping, the three actions, a target column deleted mid-dialog, two columns filling one, replace mode and the type-checked writes.pnpm check,pnpm testandpnpm buildpass in theuipackage.🤖 Generated with Claude Code
Greptile Summary
This PR adds explicit per-file-column metadata import actions, preserves existing column identities when filling them, supports replacing all metadata, prevents normalized-label collisions, and enforces value-type compatibility during writes. It also adds focused utility tests and refreshes the shared Platforma build and SDK dependencies.
Important touched terms
ImportMode— Determines whether an import keeps existing metadata columns or deletes and rebuilds them. This PR introduceskeepandreplacemodes and exposes them in the dialog.ColumnTarget— Describes one imported column’s action. This PR definesnew,existing, andignoretargets.MetadataColumnMapping— Maps each source-file column index to itsColumnTarget. This PR adds the mapping as dialog state and passes it into column resolution.defaultColumnMapping— Produces untouched-import defaults. It now auto-fills the first compatible, normalized-name match, avoids claiming an existing column twice, and marks skipped columns as ignored.resolveMetadataColumns— Converts mappings into existing or newly created model columns. It now preserves selected column identities, recovers from deleted targets, and assigns collision-free labels.isColumnTypeCompatible— Defines allowable source-to-target type relationships. String targets accept numeric sources, Double targets accept Double or Long, and Long targets accept only Long.populateMetadataFromRow— Writes imported values into resolved metadata columns. It now stringifies numeric values for String columns and rejects strings for numeric columns.Confidence Score: 5/5
The PR appears safe to merge, with no outstanding actionable failures identified in the current changes.
The current implementation consistently resolves each source column to an ignored, new, or compatible existing target, prevents normalized-label collisions, and preserves existing column identity when requested. Both previous findings were manually resolved and therefore do not remain outstanding.
Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[Imported file column] --> B{Sample-name column?} B -- Yes --> C[Ignore for metadata] B -- No --> D{Import mode} D -- Replace --> E[Create collision-free new column] D -- Keep --> F{Configured target} F -- Ignore --> C F -- New --> E F -- Existing --> G{Target still exists?} G -- Yes --> H[Reuse existing column identity] G -- No --> E E --> I[Write type-checked values] H --> IReviews (2): Last reviewed commit: "Never create a metadata column under a n..." | Re-trigger Greptile