Repository navigation
fix(plugin-form): DrawerForm holds the loading state until the first record read lands (#10190) - #10256
Merged
objectstack-fleet[bot] merged 3 commits intoSep 24, 2026
Conversation
…record read lands The fields effect and the fetch effect both key on objectSchema, so the commit that publishes the schema runs both; the fields effect, declared second, ended the loading state unconditionally and painted an empty, editable form while findOne was still in flight. The landing record then replaced whatever had been typed. The fields effect now ends loading only when no record read is outstanding (loadedRecordIdRef vs schema.recordId), the same ref the swap path already uses. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LkCKMa5bvrw3L4ezcNXEXW
…angeset for objectui#10190 editAllowedFieldAndSubmit waited only for input[name="actual_value"] to exist, which is the window a container that paints before findOne lands leaves open (ModalForm still does). It now waits for RECORD.actual_value to be on screen before typing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LkCKMa5bvrw3L4ezcNXEXW
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
github-merge-queue
Bot
removed this pull request from the merge queue due to a conflict with the base branch
Sep 24, 2026
Resolves the DrawerForm.tsx conflict with objectui#10251 (customFields merge). Its separate customFields early branch is gone as landed; the fields effect's two remaining setLoading(false) exits (sections branch and the final flat build) both go through the recordReadOutstanding gate. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LkCKMa5bvrw3L4ezcNXEXW
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
objectstack-fleet
Bot
deleted the
claude/issue-10190-drawerform-first-load-window
branch
September 24, 2026 14:43
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.
Fixes #10190
What
DrawerFormno longer paints an editable form while the FIRST record read is in flight. The field-building effect now ends the loading state only when no record read is outstanding, judged by the sameloadedRecordIdRefthe record-swap path already uses (no new flag). A load the fetch effect started is ended by the fetch effect.Mechanism, reproduced (the card's reading was a reading; it is now a measurement)
Both effects key on
objectSchema, so the commit that publishes the schema runs both, fetch first: the fetch effect enters loading and firesfindOne, and the fields effect, declared second, used to callsetLoading(false)unconditionally. Measured with a realDrawerFormand afindOneheld open by the test (deferred promise), then typingtypedwhile it is pending, then resolving it with a record whosetitleisRecord One:fields, base0aacecc08typedRecord One(typed value lost)sections, base0aacecc08typedRecord One(typed value lost)fields, this branchRecord Onesections, this branchRecord OneThis discriminates between the two readings the card named. A stale
handleSubmitclosure would leave the DOM showingtypedand lose it only on submit; instead the DOM itself flips fromtypedtoRecord Onewhen the record lands, which is the landing record replacing the form's values. The committed CONTROL row closes the other side: a value typed AFTER the record has landed is exactly what reachesupdate(title: 'typed'), so the submit closure is not stale.Tests
packages/plugin-form/src/__tests__/drawerFirstLoadWindow-10190.test.tsx(flat and sectioned shapes): no editable input while the first read is held open; a value typed after landing is the value submitted (CONTROL); create mode reads no record and renders editable straight away.982dd06throughablation-replace.mjs(anchorif (!recordReadOutstanding) setLoading(false);swapped forvoid recordReadOutstanding; setLoading(false);, anchor x1 to x0, blob7de35968397ato307856385b75): the two window rows went red (Tests 2 failed | 3 passed (5)), the CONTROL and create rows stayed green; restore verified as blob == HEAD andgit diff HEADempty. A first attempt used a replacement that is a substring of the anchor, which the tool refused as a no-op (count 6 to 6) and restored; it measured nothing.fieldSecurityPayload.test.tsx: theeditAllowedFieldAndSubmithelper now waits forRECORD.actual_valueto be ON SCREEN before typing, not merely for the input to exist. After this fix the drawer row no longer needs it, but the ModalForm row does (see below: ModalForm still holds the same window). No FLS assertion was touched, skipped or loosened.Local results, all at HEAD
f390b0c(tree clean, merged withorigin/main, which had not moved from the base):pnpm exec vitest run packages/plugin-form/src/fieldSecurityPayload.test.tsxx5, from the repo root: 5 of 5 exit 0,Tests 12 passed (12)each.pnpm exec vitest run packages/plugin-form/:Test Files 113 passed (113),Tests 1100 passed | 1 skipped (1101).pnpm --filter @object-ui/plugin-form type-checkexit 0, after building the dependency closure (--filter '@object-ui/plugin-form^...' build);tsc -p tsconfig.test.json --listFilesincludes both changed test files.pnpm --filter @object-ui/plugin-form lintexit 0 (0 errors).DrawerForm.tsxcarries the same 22 warnings, by rule, as at the base.check:vi-mock-specifiers,check:vi-mock-inherit,check:vi-mock-override-shape,check:test-path-roots,check:changeset-claims,check:pending-changeset-literals,check:new-line-citations,check:control-bytes,check-changeset-presence.mjs,check-changeset-no-major.mjs: all exit 0.pnpm lintand the fullpnpm testfarm. Those are CI's.Acceptance notes
typedbecomesRecord Onewhen the record lands, in both flat and sectioned shapes. Its fields effect ends loading unconditionally, the same way. Not edited here: objectui#9849 step two ownsModalFormnext.schemaReady/recordReady). This takes the narrower route of reusing the existing record ref, so there is one source of truth for "which record the form holds" instead of a second boolean that can disagree with it.fieldson each render) could previously end the swap's loading state early. It now leaves that to the fetch effect too. This half is a reading of the code, not a measurement: no test here rebuildsfieldsacross a swap..changeset/10190-drawerform-first-load-window.md, patch for@object-ui/plugin-form.Session:
https://claude.ai/code/session_01LkCKMa5bvrw3L4ezcNXEXW(seatdomain:ui#2).Generated by Claude Code