Repository navigation
fix(canvas): forward drag events through CreateNodePanel backdrop - #1076
Conversation
The backdrop div (added in c5cde38) sits at z-index 29 over the entire canvas, blocking HTML5 drag-and-drop from reaching ReactFlow. Since the browser requires preventDefault() in onDragOver to allow a drop, events were silently swallowed and onDrop on ReactFlow never fired. Forward onDrop and onDragOver from the FlowGraph context to the backdrop so drags from the Add Node panel land at the correct canvas position. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
No description provided. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthrough
ChangesBackdrop drag-and-drop wiring
Possibly Related PRs
Suggested Reviewers
Poem
🎯 2 (Simple) | ⏱️ ~10 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…n, add drag-through-backdrop
VALIDATION OVERHAUL:
- Delete csp-safe-validator.ts (cfworker/json-schema wrapper) entirely.
The cfworker validator silently crashed on the engine's non-standard
"object" key in generated JSON schemas, causing formDataValid to
always return true — meaning nodes with missing API keys never showed
the red gear icon or validation snackbar.
- Switch both rjsf.ts and NodeConfigPanel.tsx to @rjsf/validator-ajv8,
which tolerates unknown schema keywords and correctly handles
dependencies/oneOf resolution.
- Add recursive stripEmptyStrings() to rjsf.ts so that empty string
values ("") are removed before validation — JSON Schema's "required"
only checks key presence, so "" was passing validation for fields
like apikey that must be filled in.
- Add 'unsafe-eval' to CSP in both template.html and ProjectProvider.ts
because AJV compiles schemas via new Function() at runtime.
RE-VALIDATION ON ASYNC SERVICE CATALOG LOAD:
- Move configSnackbar state and auto-hide timer from FlowCanvas into
FlowGraphContext so both loadData and the servicesJson effect can
set the snackbar message.
- loadData now re-validates every node's formDataValid against current
schemas on project load and returns the unconfigured count.
- Add useEffect([servicesJson]) in FlowGraphContext that re-validates
all nodes when the service catalog arrives asynchronously. This is
necessary because servicesJson is empty when loadData first runs on
canvas mount — without this effect, nodes loaded before the catalog
arrives would never get validated.
CREATE-NODE PANEL DRAG FIX (PR #1076):
- Forward onDragOver and onDrop through the CreateNodePanel backdrop
div so that dragging a node from the panel onto the canvas works
even when the backdrop overlay intercepts the drop event.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* cherry-pick batch 1: e50ea6c..36ef456 (squashed) * feat(shell): add subscription gate to block unsubscribed apps Previously the ShellLayout only had an auth gate — it checked whether the user was logged in before rendering an app that requires authentication. However there was no equivalent check for subscription status. This meant a logged-in user could navigate directly to a subscription-based app (e.g. Brandy) and see the full app UI even without an active subscription. Add a subscription gate that mirrors the auth gate pattern: 1. Compute `subGateActive` — true when the user IS authenticated but the active app's `appStatus` is 'unsubscribed' (and it's not the default/home app). 2. An effect emits `shell:subscribe` with the full manifest entry, which triggers the existing CheckoutFlow to open the Stripe checkout modal automatically. 3. A `subGateTriggeredRef` prevents re-emitting for the same app (same pattern as `authGateTriggeredRef`). 4. The client area renders a "Subscription required" placeholder instead of loading the app component while the gate is active. Once the Stripe webhook fires after successful checkout, the server pushes an updated identity with `appStatus: 'subscribed'`, which propagates through Shell → WorkspaceContext → ShellLayout, clearing `subGateActive` and allowing the app to render. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(billing): shared PlanPicker, auth provider refactor, announcements, and checkout improvements This commit consolidates several billing and UI improvements across shell-ui, shared-ui, and client-typescript. ## Shared PlanPicker component (shared-ui) Extract the plan card picker from CheckoutModal into a standalone PlanPicker component so it can be reused by both the checkout flow and the public pricing page. - New PlanPicker.tsx: interval toggle (month/year), plan card grid, action plan support (link/mailto CTA buttons vs selectable cards), auto-selection when toggling intervals. - CheckoutModal simplified to a two-step flow: PlanPicker → PaymentForm. All plan card rendering and interval logic moved to PlanPicker. - New CheckoutPlan.action and PlanAction types in checkout/types.ts to support non-checkout plan cards (Free tier → GitHub link, Enterprise → mailto). - Matching PlanAction and StripePlan types added to client-typescript billing types so the SDK can return rich plan metadata (description lines, display amounts, action, order, credit grants). - Exports added to shared-ui barrel (PlanPicker, PlanPickerProps, PlanAction, useAnnouncements, Announcement). ## Auth provider delegation (shell-ui) Refactor ConnectionManager to accept an IAuthProvider interface instead of managing PKCE OAuth internally: - Shell.tsx initializes CloudAuthProvider and passes it to cm.init(). - ConnectionManager.startOAuth() delegates to authProvider.signIn() when available, with legacy PKCE fallback. - CloudAuthProvider.signIn() uses location.replace() instead of location.href so the browser back button skips expired Zitadel authRequestID pages. - Legacy zitadelUrl/zitadelClientId options marked @deprecated. ## Announcements (shared-ui) - New useAnnouncements hook: fetches announcements from the rocketride-org/announcements GitHub repo, caches for 1 hour, filters by valid_from/valid_until dates. - SidebarFooter updated to use the hook instead of hardcoded announcements array. Renders markdown in titles/bodies. Adds prev/next navigation buttons when multiple announcements exist. Gracefully hides the ticker when no announcements are available. ## Other changes - Sidebar: collapsed state shows the same resolved app icon instead of always showing the RocketRide mark. - registerApp.js: removed build-time stripeProductId validation (Stripe products are now created at runtime via seed_apps). Added billing section passthrough to apps.json for seed_apps to provision Stripe products. - tasks.js: exclude shared-ui from remote UI module list (it's a library, not a deployable remote). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(canvas): replace cfworker validator with AJV, fix node validation, add drag-through-backdrop VALIDATION OVERHAUL: - Delete csp-safe-validator.ts (cfworker/json-schema wrapper) entirely. The cfworker validator silently crashed on the engine's non-standard "object" key in generated JSON schemas, causing formDataValid to always return true — meaning nodes with missing API keys never showed the red gear icon or validation snackbar. - Switch both rjsf.ts and NodeConfigPanel.tsx to @rjsf/validator-ajv8, which tolerates unknown schema keywords and correctly handles dependencies/oneOf resolution. - Add recursive stripEmptyStrings() to rjsf.ts so that empty string values ("") are removed before validation — JSON Schema's "required" only checks key presence, so "" was passing validation for fields like apikey that must be filled in. - Add 'unsafe-eval' to CSP in both template.html and ProjectProvider.ts because AJV compiles schemas via new Function() at runtime. RE-VALIDATION ON ASYNC SERVICE CATALOG LOAD: - Move configSnackbar state and auto-hide timer from FlowCanvas into FlowGraphContext so both loadData and the servicesJson effect can set the snackbar message. - loadData now re-validates every node's formDataValid against current schemas on project load and returns the unconfigured count. - Add useEffect([servicesJson]) in FlowGraphContext that re-validates all nodes when the service catalog arrives asynchronously. This is necessary because servicesJson is empty when loadData first runs on canvas mount — without this effect, nodes loaded before the catalog arrives would never get validated. CREATE-NODE PANEL DRAG FIX (PR #1076): - Forward onDragOver and onDrop through the CreateNodePanel backdrop div so that dragging a node from the panel onto the canvas works even when the backdrop overlay intercepts the drop event. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(sdk): sync Python billing types with TypeScript SDK The TypeScript SDK's billing.ts was updated with new fields during the billing/checkout refactor but the Python SDK was not kept in sync. - Add PlanAction TypedDict (type, url, subject, label) for action plans (Free → GitHub link, Enterprise → mailto) - Expand StripePlan with label, amount, cents, currency, description, action, order, credits, and labels fields to match the TS interface - Update StripePlan.interval to include '' for non-recurring plans - Add credits and creditLabels to BillingDetail - Add labels to CreditBalance - Export PlanAction from types/__init__.py and __all__ Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address CodeRabbit and reviewer feedback on billing PR - chat-ui/dropper-ui: document register tasks as intentional no-ops (standalone pages, not shell-ui MF remotes) - SDK constants: drop :80 from HTTPS cloud URI — port 80 is HTTP default, not HTTPS; aligns VSCode, TS SDK, and Python SDK on same endpoint - SidebarFooter: sanitize announcement link URLs — only allow http(s):// schemes to prevent javascript: injection from remote JSON; add target="_blank" rel="noopener noreferrer"; add type="button" and aria-label to prev/next announcement buttons - useAnnouncements: add 10s AbortSignal timeout to fetch - PlanPicker: reset interval back to 'month' when plans change and month plans are available (was only switching to 'year', never back) - types.ts: add 'one_time' to CheckoutPlan.interval union — PlanPicker already references it in the filter logic - transformers.py: add rocketlib debug() on tokenizer/processor fallback paths so load failures are traceable - Shell.tsx: remove debug console.log statements left from development Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…n, add drag-through-backdrop
VALIDATION OVERHAUL:
- Delete csp-safe-validator.ts (cfworker/json-schema wrapper) entirely.
The cfworker validator silently crashed on the engine's non-standard
"object" key in generated JSON schemas, causing formDataValid to
always return true — meaning nodes with missing API keys never showed
the red gear icon or validation snackbar.
- Switch both rjsf.ts and NodeConfigPanel.tsx to @rjsf/validator-ajv8,
which tolerates unknown schema keywords and correctly handles
dependencies/oneOf resolution.
- Add recursive stripEmptyStrings() to rjsf.ts so that empty string
values ("") are removed before validation — JSON Schema's "required"
only checks key presence, so "" was passing validation for fields
like apikey that must be filled in.
- Add 'unsafe-eval' to CSP in both template.html and ProjectProvider.ts
because AJV compiles schemas via new Function() at runtime.
RE-VALIDATION ON ASYNC SERVICE CATALOG LOAD:
- Move configSnackbar state and auto-hide timer from FlowCanvas into
FlowGraphContext so both loadData and the servicesJson effect can
set the snackbar message.
- loadData now re-validates every node's formDataValid against current
schemas on project load and returns the unconfigured count.
- Add useEffect([servicesJson]) in FlowGraphContext that re-validates
all nodes when the service catalog arrives asynchronously. This is
necessary because servicesJson is empty when loadData first runs on
canvas mount — without this effect, nodes loaded before the catalog
arrives would never get validated.
CREATE-NODE PANEL DRAG FIX (PR #1076):
- Forward onDragOver and onDrop through the CreateNodePanel backdrop
div so that dragging a node from the panel onto the canvas works
even when the backdrop overlay intercepts the drop event.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(vscode,cloud,models): cloud URI resolution, replica constants, bootstrap logging Cloud URI: - Remove .config file; all build-time env vars now come from .env - VSCode cloud mode: ignore stale hostUrl from settings, use build-time ROCKETRIDE_URI or default to https://api.rocketride.ai - rsbuild: default ROCKETRIDE_URI to https://api.rocketride.ai so the CloudPanel probe fires correctly on first boot - Update docs and SDK references from cloud.rocketride.ai to api.rocketride.ai Replica Manager: - Restore drain-time scaling constants (CONST_SCALE_UP_DRAIN_TIME_S etc.) that were renamed to queue-depth constants in 51f3b0d but never consumed; replica_manager.py still imports the old names and would crash on import Bootstrap debugging: - Add console.log tracing to shell-ui bootstrap and finishConnect to diagnose first-login hang on cloud.rocketride.ai Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(builder): auto-discover *-ui modules and add ui:register command Replace hardcoded app lists in ui:build and ui:clean with dynamic registry lookup — any registered *-ui module (OSS or overlay) is picked up automatically without maintaining a manual list. Add ui:register aggregate task that writes all app manifest entries into apps.json without bundling. Used by the SaaS engine CI to generate the complete app catalog for DB seeding without the cost of a full UI build. Add no-op :register actions to chat-ui and dropper-ui (hand-written modules that don't use createAppModule and have no apps.json entry). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(shell-ui): log MF remotes on registration Add a console.log in registerAndMapApps() that prints each Module Federation remote's moduleId and entry URL right after registerRemotes() is called. This makes it easy to verify which app bundles the shell is wiring up and where they resolve to. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor(shell): move MF app bundles from /shell/apps/ to /apps/ The /shell/apps/ path for Module Federation remote bundles created confusion and bugs: the shell dev server's publicDir pointed at dist/server/static/ expecting bundles at static/shell/apps/, but the builder output them to build/apps/. The extra /shell/ nesting also forced the CI workflow to maintain duplicate copy targets. This commit gives app bundles their own top-level /apps/ route, separating them from the shell's own assets (/shell/ for JS/CSS/themes). Build system: - registerApp.js: entry, icon, and readme URLs now use /${APPS_BASE}/ instead of /shell/${APPS_BASE}/ (e.g. /apps/home-ui/remoteEntry.js) - appModule.js: copy destination changed from dist/server/static/shell/apps/<name> to dist/server/static/apps/<name> Server: - shell.py: added _apps_root (static/apps/) and new apps_static() handler that serves MF bundles with path-traversal protection and 404 responses (no SPA fallback — these are JS/CSS assets, not routes) - shell/__init__.py: registered GET /apps/{file_path:path} route alongside the existing /shell/ route Shell host (dev): - rsbuild.config.mts: dev publicDir now serves from build/ (via ROCKETRIDE_BUILD_ROOT) instead of dist/server/static/, so /apps/* resolves directly to the builder output at build/apps/* - bootstrap.tsx: import Shell and AppManifestEntry from relative paths instead of bare 'shell-ui' — MF intercepts bare imports and tries to load from the share scope, but the host hasn't registered its own factory yet, causing an undefined factory error (RUNTIME-006) Types: - client.ts: updated AppManifestEntry.icon docstring example path Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(build): restore .config with public build-time defaults The .config file was accidentally removed in a previous commit. Without it, getenv() returns empty strings for RR_ZITADEL_URL, RR_ZITADEL_CLIENT_ID, and RR_STRIPE_PUBLISHABLE_KEY unless the developer has a local .env that sets them — causing "Zitadel not configured" in shell-ui and breaking OAuth login. This file provides safe-to-commit public defaults (OAuth client IDs, Zitadel issuer URL, Stripe publishable key, localhost server URI) that getenv() loads first, with .env layered on top as overrides. CI also relies on .config for the base values before writing its own .env. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(shell): stop post-auth MF re-registration from wiping probe remotes After auth, Shell.tsx called registerAndMapApps() with only the user's desktop apps (ConnectResult.apps), which invoked registerRemotes() with force:true — wiping the full probe catalog. Apps like home-ui that were registered from the probe but not in the user's desktop list became unloadable, causing the shell to hang on "Loading...". MF remote registration (moduleId → remoteEntry URL) only needs to happen once from the probe. Post-auth, the URLs don't change — the shell only needs to overlay desktop metadata (appStatus, onDesktop) onto the existing probe entries for UI display purposes. - Remove registerAndMapApps import from Shell.tsx (no longer used) - Replace the apps useMemo with a simple metadata overlay that merges desktop fields onto probe entries without touching MF registration Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(model-server): fallback to slow tokenizer for SentencePiece models + fix workspace seed state Tokenizer: AutoTokenizer.from_pretrained() tries fast (Rust) tokenizer first; models like Davlan/xlm-roberta-base-ner-hrl use SentencePiece which can't auto-convert to Rust, causing persistent load failures in chaos tests. Now retries with use_fast=False before falling back to AutoProcessor. Workspace: set seeded=true on all load paths so downstream consumers don't block waiting for seed completion. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(shell): add subscription gate to block unsubscribed apps Previously the ShellLayout only had an auth gate — it checked whether the user was logged in before rendering an app that requires authentication. However there was no equivalent check for subscription status. This meant a logged-in user could navigate directly to a subscription-based app (e.g. Brandy) and see the full app UI even without an active subscription. Add a subscription gate that mirrors the auth gate pattern: 1. Compute `subGateActive` — true when the user IS authenticated but the active app's `appStatus` is 'unsubscribed' (and it's not the default/home app). 2. An effect emits `shell:subscribe` with the full manifest entry, which triggers the existing CheckoutFlow to open the Stripe checkout modal automatically. 3. A `subGateTriggeredRef` prevents re-emitting for the same app (same pattern as `authGateTriggeredRef`). 4. The client area renders a "Subscription required" placeholder instead of loading the app component while the gate is active. Once the Stripe webhook fires after successful checkout, the server pushes an updated identity with `appStatus: 'subscribed'`, which propagates through Shell → WorkspaceContext → ShellLayout, clearing `subGateActive` and allowing the app to render. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(billing): shared PlanPicker, auth provider refactor, announcements, and checkout improvements This commit consolidates several billing and UI improvements across shell-ui, shared-ui, and client-typescript. ## Shared PlanPicker component (shared-ui) Extract the plan card picker from CheckoutModal into a standalone PlanPicker component so it can be reused by both the checkout flow and the public pricing page. - New PlanPicker.tsx: interval toggle (month/year), plan card grid, action plan support (link/mailto CTA buttons vs selectable cards), auto-selection when toggling intervals. - CheckoutModal simplified to a two-step flow: PlanPicker → PaymentForm. All plan card rendering and interval logic moved to PlanPicker. - New CheckoutPlan.action and PlanAction types in checkout/types.ts to support non-checkout plan cards (Free tier → GitHub link, Enterprise → mailto). - Matching PlanAction and StripePlan types added to client-typescript billing types so the SDK can return rich plan metadata (description lines, display amounts, action, order, credit grants). - Exports added to shared-ui barrel (PlanPicker, PlanPickerProps, PlanAction, useAnnouncements, Announcement). ## Auth provider delegation (shell-ui) Refactor ConnectionManager to accept an IAuthProvider interface instead of managing PKCE OAuth internally: - Shell.tsx initializes CloudAuthProvider and passes it to cm.init(). - ConnectionManager.startOAuth() delegates to authProvider.signIn() when available, with legacy PKCE fallback. - CloudAuthProvider.signIn() uses location.replace() instead of location.href so the browser back button skips expired Zitadel authRequestID pages. - Legacy zitadelUrl/zitadelClientId options marked @deprecated. ## Announcements (shared-ui) - New useAnnouncements hook: fetches announcements from the rocketride-org/announcements GitHub repo, caches for 1 hour, filters by valid_from/valid_until dates. - SidebarFooter updated to use the hook instead of hardcoded announcements array. Renders markdown in titles/bodies. Adds prev/next navigation buttons when multiple announcements exist. Gracefully hides the ticker when no announcements are available. ## Other changes - Sidebar: collapsed state shows the same resolved app icon instead of always showing the RocketRide mark. - registerApp.js: removed build-time stripeProductId validation (Stripe products are now created at runtime via seed_apps). Added billing section passthrough to apps.json for seed_apps to provision Stripe products. - tasks.js: exclude shared-ui from remote UI module list (it's a library, not a deployable remote). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(canvas): replace cfworker validator with AJV, fix node validation, add drag-through-backdrop VALIDATION OVERHAUL: - Delete csp-safe-validator.ts (cfworker/json-schema wrapper) entirely. The cfworker validator silently crashed on the engine's non-standard "object" key in generated JSON schemas, causing formDataValid to always return true — meaning nodes with missing API keys never showed the red gear icon or validation snackbar. - Switch both rjsf.ts and NodeConfigPanel.tsx to @rjsf/validator-ajv8, which tolerates unknown schema keywords and correctly handles dependencies/oneOf resolution. - Add recursive stripEmptyStrings() to rjsf.ts so that empty string values ("") are removed before validation — JSON Schema's "required" only checks key presence, so "" was passing validation for fields like apikey that must be filled in. - Add 'unsafe-eval' to CSP in both template.html and ProjectProvider.ts because AJV compiles schemas via new Function() at runtime. RE-VALIDATION ON ASYNC SERVICE CATALOG LOAD: - Move configSnackbar state and auto-hide timer from FlowCanvas into FlowGraphContext so both loadData and the servicesJson effect can set the snackbar message. - loadData now re-validates every node's formDataValid against current schemas on project load and returns the unconfigured count. - Add useEffect([servicesJson]) in FlowGraphContext that re-validates all nodes when the service catalog arrives asynchronously. This is necessary because servicesJson is empty when loadData first runs on canvas mount — without this effect, nodes loaded before the catalog arrives would never get validated. CREATE-NODE PANEL DRAG FIX (PR #1076): - Forward onDragOver and onDrop through the CreateNodePanel backdrop div so that dragging a node from the panel onto the canvas works even when the backdrop overlay intercepts the drop event. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(sdk): sync Python billing types with TypeScript SDK The TypeScript SDK's billing.ts was updated with new fields during the billing/checkout refactor but the Python SDK was not kept in sync. - Add PlanAction TypedDict (type, url, subject, label) for action plans (Free → GitHub link, Enterprise → mailto) - Expand StripePlan with label, amount, cents, currency, description, action, order, credits, and labels fields to match the TS interface - Update StripePlan.interval to include '' for non-recurring plans - Add credits and creditLabels to BillingDetail - Add labels to CreditBalance - Export PlanAction from types/__init__.py and __all__ Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address CodeRabbit and reviewer feedback on billing PR - chat-ui/dropper-ui: document register tasks as intentional no-ops (standalone pages, not shell-ui MF remotes) - SDK constants: drop :80 from HTTPS cloud URI — port 80 is HTTP default, not HTTPS; aligns VSCode, TS SDK, and Python SDK on same endpoint - SidebarFooter: sanitize announcement link URLs — only allow http(s):// schemes to prevent javascript: injection from remote JSON; add target="_blank" rel="noopener noreferrer"; add type="button" and aria-label to prev/next announcement buttons - useAnnouncements: add 10s AbortSignal timeout to fetch - PlanPicker: reset interval back to 'month' when plans change and month plans are available (was only switching to 'year', never back) - types.ts: add 'one_time' to CheckoutPlan.interval union — PlanPicker already references it in the filter logic - transformers.py: add rocketlib debug() on tokenizer/processor fallback paths so load failures are traceable - Shell.tsx: remove debug console.log statements left from development Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(sdk): sync StripePlan.interval with CheckoutPlan — add 'one_time' Both TS and Python SDK StripePlan types now include 'one_time' in the interval union, matching CheckoutPlan in shared-ui. Without this, SDK consumers can't pass one-time plans to CheckoutModal without a cast. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
z-index: 29over the entire canvas withposition: absolute; inset: 0preventDefault()inonDragOverto allow a drop — the backdrop had no drag handlers, so the browser blocked all drops silentlyonDropnever fired, so nodes dragged from the Add Node panel were never placedFix: forward
onDragOverandonDropfromFlowGraphContextto the backdrop div so drops land at the correct canvas position while the backdrop still closes the panel on click.Test plan
🤖 Generated with Claude Code
Summary by CodeRabbit