Conversation
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Automations to automatically generate PRs for you. |
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.
Closes #2996.
Before / After
Customer.SupportRepId → Employee.EmployeeIdon the bundled Chinook sample. One label column is the default the heuristic picks, and it cannot tell the eight employees apart.Title)LastName,FirstName)Three rows read
Sales Support Agentand two readIT Staff, so picking the right one is guesswork. With both name columns ticked every row names a person.The chooser itself, reached from Label in the footer.
EmployeeIdis absent from the list because the key is already the first thing every row shows:The problem
The foreign key value picker's Label menu selected exactly one column of the referenced table, or None. That is not enough when a parent row's human identity spans two columns, which is exactly what a composite
UNIQUEconstraint says it does.The reporter's SQLite schema has
alimentiwithUNIQUE(descrizione, marchio)andprezzi.alimento_id REFERENCES alimenti(id). Picking a value withmarchioas the label lists:Six rows nobody can tell apart. Choosing
descrizioneinstead hides themarchio. There was no way to see both.Root cause
Not a missing feature bolted onto a working design: the label was typed as one optional column at five boundaries, and none of them could carry a list without a signature change.
ForeignKeyLabelChoicecase column(String)ForeignKeyLabelColumn.resolve-> ForeignKeyLookupColumn?ForeignKeyLookupQuery.selectedColumns(key:label:), label optionalForeignKeyLookupService.rows(from:)1ForeignKeyPickerViewfooterPicker(.menu)So this widens all five together rather than special-casing one of them.
The fix
Label in the picker's footer now drills the same popover in to a chooser: the referenced table's columns as checkboxes, a search field past five columns, None to clear, Done to go back. Ticked columns show beside the key in the table's own order and the search matches any of them.
Why a drill-in and not a menu
Measured, not assumed:
menuActionDismissBehavior(.disabled)is@available(macOS, unavailable). A compiled probe fails with'disabled' is unavailable in macOS.keepsMenuPresented,dismissBehavior,stayOpenorkeepOpenanywhere in the macOS 27 SDK headers. UIKit'skeepsMenuPresentedhas no AppKit twin.NSMenuof checkmarked items:NSMenuDidEndTrackingNotification, then the action fires, thenpopUpreturns. The menu closes on every click.So a menu of checkmarks costs one reopen per column. The HIG rules out the other two options over a popover: "Never show a cascade or hierarchy of popovers" and "Don't show another view over a popover... except for an alert". It also says a pop-up button is for "a flat list of mutually exclusive options" and to use something else to "let people select multiple items", which is what the old
Pickerwas.The chooser is built on
ColumnCheckList, extracted fromColumnVisibilityPopoverso the grid's column popover and this one are the same control rather than two copies of it.Why the table's own column order
Not tick order, and no reorder handle. DBeaver numbers its dictionary columns by tick order and its own
AttributesSelectorPagecompacts the numbering on untick, so changing the order there means unticking everything and re-ticking. The referenced table's declaration order needs no control at all and gives the reporter's expected result. The trade-off is real and stated: a natural key declared out of sequence reads in declaration order. The stored value is an ordered array, so a custom order has somewhere to live if it is ever asked for.Also skipped, deliberately: DBeaver's free-text "Custom expression for description" and its global delimiter preference. In its own source, ticking a checkbox overwrites the text field and only the text field is saved, so the two inputs fight.
Two shipped bugs this change absorbs
Both live in the code being rewritten, and the feature would carry them forward.
The referenced key column was offered as a label, and choosing it showed no label at all, forever. The menu was built from the unfiltered column list;
resolvehonoured the stored name with no key check;selectedColumnsthen returned[key]alone;rows(from:)computed no label index; every row rendered bare. The choice was persisted, survived a restart, and was inherited by every other column pointing at the same table. Nothing reported that it could not be honoured. The chooser no longer lists the key column, andresolvenever returns it. A choice that named the key alongside real columns keeps those columns; a choice that named nothing but the key is honoured as no label, because that is what it has been showing, and clearing it is one click on the chooser.The picker reported "No matching rows" for a term it had never searched for. A chosen column that takes no
LIKEcarries no predicate. When the key could not take the term either, the filter list was empty, no query was sent, and the empty result read as a search that had run. On the reporter's schema withkcal(REAL) as the label, typing a word said "No matching rows" while typing a number still worked, so the search looked intermittently broken.ForeignKeyLookupServicenow returns an outcome that tells the two apart, and the picker says No text column to search.Persistence
ForeignKeyLabelChoicekeeps its three states and gains a list payload:0xFF0xFE+ JSON array0xFEjoins0xFFas a sentinel on the same argument: no Unicode scalar's UTF-8 contains either byte, so neither can begin a column name. A comma-joined string would not do, because a comma is a legal column name. Nothing migrates on upgrade, and an unreadable payload reads as "nothing chosen" rather than becoming a quoted identifier.Verified
verify.sh generateverify.sh buildverify.sh test(9 suites, 104 cases)verify.sh lint(17 files)verify.sh docsSuites:
ForeignKeyLabelChoice(new),ForeignKeyLabelText(new),ForeignKeyLabelColumn,ForeignKeyLookupQuery,ForeignKeyLabelColumnStore,ForeignKeyPickerEntry,TableScopedSettingsRegistry,StringCatalogIntegrity,CompiledStringsFormat.The screenshots above come from a Debug build driven with
osascriptunderTABLEPRO_UI_TEST_SANDBOX, so they are the real control rather than a mock-up. The same run produced the two docs images.A second model read the diff: Codex is out of credits until 2026-09-22, so
/code-review highdid the pass. It raised five findings. Three are fixed here: the five new strings were missing fromLocalizable.xcstrings; a stored choice naming only the key column re-ran the heuristic instead of standing as no label; andtermIsNotSearchablestayed set through the next search. Two were declined: the chooser's%d of %dheader counts the heuristic's pick, which is accurate because that box is ticked, and nothing caps how many label columns can be chosen, whichLIMIT 50already bounds and where a cap would silently ignore a ticked column.ForeignKeyPickerUITestsgains two cases on Chinook'sCustomer.SupportRepId → Employee, whose rows only name a person once bothLastNameandFirstNameare chosen: one assertsPeacock, Janerenders beside the key, the other searchesJane, a term living only in the second chosen column, and asserts the row is still found.Docs: the Label paragraph in
docs/features/data-grid.mdx.