refactor(FR-2977): unify revision-source prefill in DeploymentAddRevisionModal#7602
Conversation
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has required the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. This stack of pull requests is managed by Graphite. Learn more about stacking. |
Coverage Report for react-coverage (./react)
File Coverage
|
||||||||||||||||||||||||||||||||||||||||||||||||||
ce82933 to
034f843
Compare
There was a problem hiding this comment.
Pull request overview
Refactors DeploymentAddRevisionModal to a render-as-you-fetch model with a single shared DeploymentAddRevisionModal_revisionSource fragment. The modal now consumes a PreloadedQuery whose variables (sourceRevisionId, hasSourceRevision) can request an id-based revision lookup via revision(id:) @include @since("25.16.0"). Both currentRevision and the optional source revision are read through the same fragment, and a single keyed effect applies the prefill — replacing the previous useLazyLoadQuery + duplicate-state pump pattern and laying the groundwork for the stacked "Duplicate as new revision" PR (#7561).
Changes:
- Introduce
DeploymentAddRevisionModal_revisionSourcefragment + exportedDeploymentAddRevisionQuery; add$sourceRevisionId/$hasSourceRevisionvariables and a conditionalrevision(id:)top-level field. - Switch the modal from
useLazyLoadQuerytousePreloadedQuery+useDeferredValue, deriveeffectiveMode='custom'when the queryRef carrieshasSourceRevision, and reduce prefill to one keyeduseEffect/useEffectEventusingappliedSourceIdRef. - Move query kickoff to
DeploymentDetailPageviauseQueryLoader, drop the local<Suspense>boundary, and gate modal render onaddRevisionQueryRef != null.
Reviewed changes
Copilot reviewed 3 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| react/src/pages/DeploymentDetailPage.tsx | Replaces useToggle with useState+useQueryLoader to preload the modal query on click; removes the local Suspense boundary. |
| react/src/components/DeploymentConfigurationSection.tsx | Updates the Add Revision button comment to reflect the render-as-you-fetch flow. |
| react/src/components/DeploymentAddRevisionModal.tsx | Adds the shared revision-source fragment, exported preloaded query, single apply-prefill effect, and locks mode to Custom when queryRef.variables.hasSourceRevision is true. |
| react/src/generated/DeploymentAddRevisionModalQuery.graphql.ts | Regenerated query artifact for the new variables and conditional revision field. |
| react/src/generated/DeploymentAddRevisionModal_revisionSource.graphql.ts | New generated fragment artifact for the shared revision-source selection. |
Files not reviewed (2)
- react/src/generated/DeploymentAddRevisionModalQuery.graphql.ts: Language not supported
- react/src/generated/DeploymentAddRevisionModal_revisionSource.graphql.ts: Language not supported
034f843 to
1b84a66
Compare
nowgnuesLee
left a comment
There was a problem hiding this comment.
Please resolve the merge conflicts.
1b84a66 to
3ba8330
Compare
3274d43 to
7623f0e
Compare
7623f0e to
8e34245
Compare
0972d0b to
15817ad
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 23 out of 27 changed files in this pull request and generated 21 comments.
Files not reviewed (4)
- react/src/generated/DeploymentAddRevisionModalQuery.graphql.ts: Language not supported
- react/src/generated/DeploymentAddRevisionModal_deployment.graphql.ts: Language not supported
- react/src/generated/DeploymentAddRevisionModal_revisionSource.graphql.ts: Language not supported
- react/src/generated/DeploymentDetailPageQuery.graphql.ts: Language not supported
13d7638 to
f914625
Compare
Add an "Add new revision from this" overflow action in each revision history table row and in the revision detail drawer. Selecting it opens DeploymentAddRevisionModal with that revision passed as `sourceRevisionFrgmt`, prefilling the Custom form from it. Rebased onto #7602 (FR-2977): the fragment-based revision-source prefill modal refactor now lives entirely in the parent PR, so this branch carries only the consumer-side changes (drawer/history menu items, fragment spreads, i18n). Drops the now-unused `FailedToPrepareNewRevision` i18n key. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add an "Add new revision from this" overflow action in each revision history table row and in the revision detail drawer. Selecting it opens DeploymentAddRevisionModal with that revision passed as `sourceRevisionFrgmt`, prefilling the Custom form from it. Rebased onto #7602 (FR-2977): the fragment-based revision-source prefill modal refactor now lives entirely in the parent PR, so this branch carries only the consumer-side changes (drawer/history menu items, fragment spreads, i18n). Drops the now-unused `FailedToPrepareNewRevision` i18n key. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add an "Add new revision from this" overflow action in each revision history table row and in the revision detail drawer. Selecting it opens DeploymentAddRevisionModal with that revision passed as `sourceRevisionFrgmt`, prefilling the Custom form from it. Rebased onto #7602 (FR-2977): the fragment-based revision-source prefill modal refactor now lives entirely in the parent PR, so this branch carries only the consumer-side changes (drawer/history menu items, fragment spreads, i18n). Drops the now-unused `FailedToPrepareNewRevision` i18n key. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
d18f4ea to
de61da7
Compare
a8f8b52 to
dca38f7
Compare
Merge activity
|
…sionModal (#7602) Resolves #7601 (FR-2977) ## Summary Base refactor for `DeploymentAddRevisionModal` so any caller (e.g. a future "Duplicate as new revision" action — see the parallel PR #7561) can hand the modal an arbitrary source `ModelRevision` to prefill from, replacing the prop-drilled fragment ref + dual-`useEffectEvent` state pump that surfaced during review of FR-2957: - **Single source fragment.** Define `DeploymentAddRevisionModal_revisionSource` on `ModelRevision` at module scope and spread it in two places: on `currentRevision` inside the modal's deployment fragment (`DeploymentAddRevisionModal_deployment`), and on whatever revision a caller wants to pass in via the new optional `sourceRevisionFrgmt` prop. Both are read via `useFragment` sharing one `$data` shape, so the extracted `applyRevisionToCustomForm(rev)` helper accepts either without an unsafe cast. - **Optional `sourceRevisionFrgmt` prop.** The modal now takes `sourceRevisionFrgmt?: DeploymentAddRevisionModal_revisionSource$key | null` alongside the required `deploymentFrgmt`. The Preset/Custom toggle remains user-controlled — `effectiveMode` defaults to `mode ?? 'preset'`, so the modal still opens in the user's persisted mode regardless of `sourceRevisionFrgmt`. When provided (e.g. "Duplicate as new revision" from a revision detail drawer), the Custom form is pre-filled from the source on **first Custom-mode entry** and the "Load current revision" alert is suppressed (it would be redundant — the form already reflects the source). When omitted, the modal behaves as the plain "Add revision" entry — Custom mode shows the alert with a button that prefills from `deployment.currentRevision` on demand. - **Apply-once gating via `useEffectEvent`.** `useEffect` keyed on `effectiveMode`. When the user lands in Custom mode for the first time in a session, `applySourcePrefillOnce` (a `useEffectEvent`) seeds the form from `sourceRevision` and flips a `hasAppliedSourcePrefill` boolean so a subsequent Preset → Custom toggle does not re-stomp the user's edits. The existing `consumePresetTransferPrefill` / `consumeCustomTransferPrefill` flows are unchanged and run from the same effect. - **i18n key** `deployment.CurrentRevisionConfigurationLoaded` for the toast that fires after Load current / source-prefill is applied. The key was first added across all 22 locales in `5ff2c0c5` (ko/ja translated, the rest as English placeholder); the 18 remaining-language translations (de, el, es, fi, fr, id, it, ms, mn, pl, pt, pt-BR, ru, th, tr, vi, zh-CN, zh-TW) were amended into the refactor commit `f91462517` while resolving review feedback. ## Notes - **Parallel with #7561 (FR-2957), not stacked.** #7561 lands the "Duplicate as new revision" menu entry / icon / i18n in the revision detail drawer and is the first intended consumer of `sourceRevisionFrgmt`. Both PRs are parented on `main`; for actual rollout this refactor needs to land first (so #7561 has a prop to pass into) but Graphite isn't enforcing the order. - **Callsite-neutral for the source-revision path on this PR.** `DeploymentDetailPage` opens the modal without `sourceRevisionFrgmt`, exactly as before — only the existing "Add revision" + "Load current revision" flows run on this branch. The Preset-mode "Load current" path is not handled in this PR; the alert is still rendered inside the Custom form, matching pre-refactor behavior. - **API evolved beyond the original issue's "`mode` + `sourceRevisionId` as props" sketch.** An earlier draft of this refactor tried a `usePreloadedQuery` / `useQueryLoader` design with `$sourceRevisionId` + `$hasSourceRevision` query variables and a `revision(id:) @include(if:)` field — that has been replaced with the plain fragment-ref prop above, which is simpler for callers (one prop, one fragment spread on their own query) and doesn't require the modal to own a separate query for the source. - **Alert action button styling.** The "Load current revision" alert's button intentionally drops `type="primary"` so the modal's footer Add Revision CTA is the only primary action — avoiding two competing primaries in one modal. - **Out of scope:** `presetTransferPrefill` / `customTransferPrefill` (the preset ↔ custom value transfer from FR-2862) — same anti-shape, but translates between two different form shapes and is a structurally different problem. - **Modal UX is unchanged** — alert copy, mode segmented control behavior, Apply button placement, footer all preserved. Pure data-flow refactor on this PR. ## Test plan - [x] **Add Revision button (sourceless)** — opens in the persisted mode, no auto-prefill, mode toggle visible, "Load current revision" alert visible in Custom. - [x] **Load current revision alert** — populates the Custom form with the deployment's current revision values (Model Folder, Runtime, image, 4 Core / 8 GiB, Single Node, etc.) and fires the success toast. - [x] **Toggle Custom ↔ Preset** — the existing transfer prefill still moves the shared values across (Custom → Preset transfers Model Folder; Preset → Custom transfers Model Folder back). - [ ] **`sourceRevisionFrgmt` consumer path** — exercised end-to-end once #7561 lands and wires the "Duplicate as new revision" entry. ## Screenshots | Preset Mode (default) | Advanced Mode — Load current revision alert | After loading current revision | |---|---|---| |  |  |  |
dca38f7 to
2827871
Compare
Add an "Add new revision from this" overflow action in each revision history table row and in the revision detail drawer. Selecting it opens DeploymentAddRevisionModal with that revision passed as `sourceRevisionFrgmt`, prefilling the Custom form from it. Rebased onto #7602 (FR-2977): the fragment-based revision-source prefill modal refactor now lives entirely in the parent PR, so this branch carries only the consumer-side changes (drawer/history menu items, fragment spreads, i18n). Drops the now-unused `FailedToPrepareNewRevision` i18n key. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rawer (#7561) Resolves #7560 (FR-2957) > **Stacked on #7602 (FR-2977).** The base PR refactors `DeploymentAddRevisionModal` to an id-based revision source. This top PR is a thin layer on top of that — menu items, i18n, icon, and the parent state that drives `sourceRevisionId`. The bulk of the original FR-2957 diff (fragment definition, dual `useEffectEvent` state pump, fragment-ref prop drilling) moved into FR-2977 in cleaner form. ## Summary - Add an **Add new revision from this** overflow action in the revision detail drawer (next to the Apply button) and in each revision history table row menu - On click, set `sourceRevisionId` on `DeploymentAddRevisionModal` so the modal opens locked to Custom mode and auto-prefills with that revision's full configuration (handled by FR-2977's machinery) - Add i18n key `deployment.AddNewRevisionFromThis` (all 21 languages) - Use `CopyOutlined` (not a branching icon) — the action copies settings into a new linear revision; it does not fork or branch the history ## Test plan - [ ] Open a deployment's revision history; verify "Add new revision from this" appears in each row's overflow menu - [ ] Open a revision detail drawer; verify the "More" (⋯) overflow next to Apply shows "Add new revision from this" - [ ] Click it — verify the Add Revision modal opens in Custom mode pre-filled with that revision's configuration (Model Folder, Runtime, image, resources, env vars, mounts) - [ ] Submit the Add Revision flow — verify a new revision is created at the linear end of the history (no branching) - [ ] Confirm the Apply button (rollback) still works as before ## Screenshots > Note: the screenshots below were captured against an earlier label ("Duplicate as new revision"). The shipped copy is **"Add new revision from this"** (`deployment.AddNewRevisionFromThis`); the layout and behavior are unchanged. | Row overflow menu | Revision detail drawer (Apply + ⋯) | Pre-filled Add Revision modal | |---|---|---| |  |  |  | The drawer header groups **Apply** with a **More (⋯)** overflow (`Space.Compact`, both primary), matching the established convention from `DeploymentConfigurationSection`. Selecting **Add new revision from this** sets `sourceRevisionId` on the modal; FR-2977's `revision(id:)` + single-effect prefill applies the values. ## What this PR no longer contains (moved to FR-2977) - The `DeploymentAddRevisionModal_duplicateRevision` fragment (replaced by `DeploymentAddRevisionModal_revisionSource` in the base PR) - The `pendingDuplicatePrefill` state + the two `useEffectEvent`s (replaced by a single derived `effectiveMode` + single apply effect in the base PR) - The fragment ref `useState` and `...DeploymentAddRevisionModal_duplicateRevision` spread on the list query (removed; the modal resolves source via id)
#7671) Resolves #7601 (FR-2977) > **Stacked on #7561 (FR-2957).** That PR adds the "Add new revision from this" entry, which is what surfaces the revision-detail drawer changes below. ## Summary Follow-up polish for FR-2977 after #7602 + #7561, focused on the deployment detail page's revision area. - **Move the "Applying revision #N" alert inside the Current Revision tab** (`DeploymentConfigurationSection`). Previously the alert sat at the deployment level between Basic Information and the revision tabs, so it was visible even on the Revision History tab where it had no context. It now lives inside the `currentRevision` tab content next to the revision detail it describes, with `marginBottom: token.marginMD` for separation from `DeploymentRevisionDetail`. - **Show the full revision UUID in `DeploymentRevisionDetail`.** The drawer/Current-Revision view rendered the 36-char revision ID inside a 2-column 183px cell, which truncated it to ~12 visible chars even with a copy button. Both `revision-number` and `revision-id` items now use `span: screens.md ? 2 : 1`, so each occupies a dedicated full-width row in the 2-column Descriptions. `BAIId` is rendered with `style={{ maxWidth: 'none' }}` so it sits at its natural width — the copy icon stays directly next to the UUID, and the `Current` / `Applying` `BAITag` follows immediately after in the same `BAIFlex`. - **Move the "Add Rules" button inline in `DeploymentAutoScalingTab`.** It used to live in the `BAICard extra` slot; it now sits inside `AutoScalingRuleList`'s toolbar to the right of the refresh button (the inline-add path the list already exposed via `hideInlineAddButton`). The card stops owning a primary button it didn't actually need. - **Misc.** Wrap `DeploymentAddRevisionModal` in a `<Suspense fallback={null}>` inside `DeploymentRevisionHistoryTab` so the row-level "Add new revision from this" action doesn't suspend the whole page on first open. ## Test plan - [x] Open a deployment with a deploying revision — verify the "Applying revision #N" alert appears inside the Current Revision tab (not above the tabs), and disappears when switching to Revision History. - [x] Open a revision via the Revision History row link — drawer shows `Revision Number` on one full-width row and `Revision ID <uuid> [copy] [Current|Applying]` on the next, full UUID visible, copy icon adjacent to the UUID. - [x] On the Current Revision tab — same layout; `Current` tag visible next to the copy icon. - [x] Auto-Scaling tab — "Add Rules" button sits to the right of the refresh button (inline), and is not duplicated in `BAICard extra`. - [x] `bash scripts/verify.sh` — TypeScript, Relay, Lint, Format all pass.

Resolves #7601 (FR-2977)
Summary
Base refactor for
DeploymentAddRevisionModalso any caller (e.g. a future "Duplicate as new revision" action — see the parallel PR #7561) can hand the modal an arbitrary sourceModelRevisionto prefill from, replacing the prop-drilled fragment ref + dual-useEffectEventstate pump that surfaced during review of FR-2957:DeploymentAddRevisionModal_revisionSourceonModelRevisionat module scope and spread it in two places: oncurrentRevisioninside the modal's deployment fragment (DeploymentAddRevisionModal_deployment), and on whatever revision a caller wants to pass in via the new optionalsourceRevisionFrgmtprop. Both are read viauseFragmentsharing one$datashape, so the extractedapplyRevisionToCustomForm(rev)helper accepts either without an unsafe cast.sourceRevisionFrgmtprop. The modal now takessourceRevisionFrgmt?: DeploymentAddRevisionModal_revisionSource$key | nullalongside the requireddeploymentFrgmt. The Preset/Custom toggle remains user-controlled —effectiveModedefaults tomode ?? 'preset', so the modal still opens in the user's persisted mode regardless ofsourceRevisionFrgmt. When provided (e.g. "Duplicate as new revision" from a revision detail drawer), the Custom form is pre-filled from the source on first Custom-mode entry and the "Load current revision" alert is suppressed (it would be redundant — the form already reflects the source). When omitted, the modal behaves as the plain "Add revision" entry — Custom mode shows the alert with a button that prefills fromdeployment.currentRevisionon demand.useEffectEvent.useEffectkeyed oneffectiveMode. When the user lands in Custom mode for the first time in a session,applySourcePrefillOnce(auseEffectEvent) seeds the form fromsourceRevisionand flips ahasAppliedSourcePrefillboolean so a subsequent Preset → Custom toggle does not re-stomp the user's edits. The existingconsumePresetTransferPrefill/consumeCustomTransferPrefillflows are unchanged and run from the same effect.deployment.CurrentRevisionConfigurationLoadedfor the toast that fires after Load current / source-prefill is applied. The key was first added across all 22 locales in5ff2c0c5(ko/ja translated, the rest as English placeholder); the 18 remaining-language translations (de, el, es, fi, fr, id, it, ms, mn, pl, pt, pt-BR, ru, th, tr, vi, zh-CN, zh-TW) were amended into the refactor commitf91462517while resolving review feedback.Notes
sourceRevisionFrgmt. Both PRs are parented onmain; for actual rollout this refactor needs to land first (so feat(FR-2957): add new-revision-from-this action in revision detail drawer #7561 has a prop to pass into) but Graphite isn't enforcing the order.DeploymentDetailPageopens the modal withoutsourceRevisionFrgmt, exactly as before — only the existing "Add revision" + "Load current revision" flows run on this branch. The Preset-mode "Load current" path is not handled in this PR; the alert is still rendered inside the Custom form, matching pre-refactor behavior.mode+sourceRevisionIdas props" sketch. An earlier draft of this refactor tried ausePreloadedQuery/useQueryLoaderdesign with$sourceRevisionId+$hasSourceRevisionquery variables and arevision(id:) @include(if:)field — that has been replaced with the plain fragment-ref prop above, which is simpler for callers (one prop, one fragment spread on their own query) and doesn't require the modal to own a separate query for the source.type="primary"so the modal's footer Add Revision CTA is the only primary action — avoiding two competing primaries in one modal.presetTransferPrefill/customTransferPrefill(the preset ↔ custom value transfer from FR-2862) — same anti-shape, but translates between two different form shapes and is a structurally different problem.Test plan
sourceRevisionFrgmtconsumer path — exercised end-to-end once feat(FR-2957): add new-revision-from-this action in revision detail drawer #7561 lands and wires the "Duplicate as new revision" entry.Screenshots