Skip to content

fix(canvas): forward drag events through CreateNodePanel backdrop - #1076

Merged
ryan-t-christensen merged 1 commit into
developfrom
fix/add-node-drop
Jun 2, 2026
Merged

ryan-t-christensen merged 1 commit into
developfrom
fix/add-node-drop

Conversation

@ryan-t-christensen

@ryan-t-christensen ryan-t-christensen commented Jun 2, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • The backdrop div introduced in c5cde38 sits at z-index: 29 over the entire canvas with position: absolute; inset: 0
  • HTML5 drag-and-drop requires preventDefault() in onDragOver to allow a drop — the backdrop had no drag handlers, so the browser blocked all drops silently
  • ReactFlow's onDrop never fired, so nodes dragged from the Add Node panel were never placed

Fix: forward onDragOver and onDrop from FlowGraphContext to the backdrop div so drops land at the correct canvas position while the backdrop still closes the panel on click.

Test plan

  • Open the Add Node panel
  • Drag a node type from the panel onto the canvas — verify it places at the drop location
  • Click outside the panel (on the canvas backdrop) — verify the panel still closes
  • Click-to-add still works

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added drag-and-drop support to the Create Node Panel. Users can now drop items directly onto the panel area while retaining the existing close-on-click functionality.

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>
@github-actions github-actions Bot added the module:ui Chat UI and Dropper UI label Jun 2, 2026
@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

No description provided.

@coderabbitai

coderabbitai Bot commented Jun 2, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 891f1b4f-5a1f-452d-8282-db99938d48cb

📥 Commits

Reviewing files that changed from the base of the PR and between 9057fea and b3bc0ad.

📒 Files selected for processing (1)
  • packages/shared-ui/src/components/canvas/components/panels/create-node/CreateNodePanel.tsx

📝 Walkthrough

Walkthrough

CreateNodePanel wires drag-and-drop event handlers from useFlowGraph into its backdrop element. The useFlowGraph hook destructuring is extended to include onDrop and onDragOver, and the backdrop <div> is updated to bind these handlers alongside the existing onClick={onClose} behavior, enabling drops on the backdrop area.

Changes

Backdrop drag-and-drop wiring

Layer / File(s) Summary
Drag-and-drop handler wiring
packages/shared-ui/src/components/canvas/components/panels/create-node/CreateNodePanel.tsx
useFlowGraph() destructuring is extended to include onDrop and onDragOver callbacks. The backdrop element is updated to bind onDragOver and onDrop handlers, enabling the panel to receive drag-and-drop events in addition to the existing close-on-click behavior.

Possibly Related PRs

  • rocketride-org/rocketride-server#304: Both PRs affect the drag-and-drop flow pipeline: CreateNodePanel now forwards backdrop onDragOver/onDrop events from useFlowGraph, while FlowProvider suppresses echoed loadData() updates and ignores intermediate drag position frames to prevent snap-back.

Suggested Reviewers

  • jmaionchi
  • stepmikhaylov
  • Rod-Christensen

Poem

🐰 A canvas backdrop, now awake,
Catches drops with every flake,
No click needed, just let it fly—
The panel listens, don't be shy!


🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: forwarding drag events through the CreateNodePanel backdrop to fix drag-and-drop functionality.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/add-node-drop

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ryan-t-christensen
ryan-t-christensen merged commit 92bf64f into develop Jun 2, 2026
34 of 36 checks passed
@ryan-t-christensen
ryan-t-christensen deleted the fix/add-node-drop branch June 2, 2026 21:14
Rod-Christensen added a commit that referenced this pull request Jun 3, 2026
…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>
Rod-Christensen added a commit that referenced this pull request Jun 4, 2026
* 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>
Rod-Christensen added a commit that referenced this pull request Jun 4, 2026
…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>
Rod-Christensen added a commit that referenced this pull request Jun 4, 2026
* 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

module:ui Chat UI and Dropper UI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants