feat(export): install requirements from dialog - #10471
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
All contributors have signed the CLA ✍️ ✅ |
There was a problem hiding this comment.
All reported issues were addressed across 13 files
Architecture diagram
sequenceDiagram
participant UI as ExportDialog (React)
participant Hook as useExportDialog
participant Toast as Toaster / Toast
participant Backend as /api/editing/install_missing_packages
participant Deps as Export Dependencies
participant Subprocess as subprocess (playwright install)
Note over UI,Subprocess: NEW: Install action from export dialog
UI->>Hook: user clicks "Install" button
alt missing-packages reason
Hook->>Hook: NEW: collect packages from reason.packages
else missing-setup reason (Playwright Chromium)
Hook->>Hook: NEW: no packages, format === "pdf"
end
Hook->>Hook: NEW: set isInstalling = true
Hook->>Backend: POST install_missing_packages<br/>{versions, manager, source: "server", installPlaywrightChromium: true}
Note over Hook,Backend: NEW: installPlaywrightChromium field in request
alt error
Backend-->>Toast: HTTPError with detail message
Toast-->>UI: CHANGED: toast rendered in portal (StyleNamespace)<br/>"Failed to install missing packages"
Hook->>Hook: error logged, isInstalling = false
else success
Backend->>Deps: CHANGED: if versions present, install packages on server<br/>if installPlaywrightChromium, also run:
Deps->>Subprocess: NEW: [sys.executable, "-m", "playwright", "install", "chromium"]
alt subprocess fails
Subprocess-->>Deps: non-zero return code
Deps-->>Backend: raise RuntimeError
Backend-->>Toast: error toast
else subprocess succeeds
Subprocess-->>Deps: exit code 0
Deps-->>Backend: success
Backend-->>Hook: 200 OK
Hook->>Hook: NEW: refetchExportAvailability()
Hook->>Hook: set isInstalling = false
end
end
Note over UI,Hook: UI re-renders with updated dependenciesAvailable state
UI->>UI: CHANGED: tabs re-enabled, install button removed, submit enabled
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
|
@cubic-dev-ai review please |
@peter-gy I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
No issues found across 15 files
Architecture diagram
sequenceDiagram
participant User as Browser User
participant Dialog as ExportDialog (React)
participant Hook as useExportDialog (React Hook)
participant Client as RequestClient (Lazy)
participant Server as marimo Server (FastAPI)
participant Deps as Export Dependencies (Python)
participant OS as Subprocess (OS)
Note over User,OS: Install Export Requirements Flow
User->>Dialog: Opens Export Dialog
Dialog->>Hook: Initialize state
Hook->>Client: getExportAvailability()
Client->>Server: GET /api/export/availability
Server-->>Client: formats[] with missingPackages / missingSetup
Client-->>Hook: ExportAvailabilityResponse
Hook->>Hook: Compute canInstall flag
Hook-->>Dialog: format status (unavailable, missing packages/setup)
Dialog->>Dialog: Render FormatNotice with Install button
alt User clicks Install button
User->>Dialog: Click "Install"
Dialog->>Hook: installRequirements()
Hook->>Hook: set isInstalling=true
Hook->>Client: sendInstallMissingPackages({manager, versions, source:"server", installPlaywrightChromium})
Client->>Client: Check connection state
alt Connection not yet open
Client->>Client: initOnce() - start WebSocket connection
end
Client->>Client: waitForConnectionOpen() - skip kernel init
Client->>Server: POST /api/kernel/install_missing_packages
Server->>Server: enforce_consumer_capability()
alt Has packages to install (versions non-empty)
Server->>Server: install_packages_on_server(manager, versions)
end
alt installPlaywrightChromium is true
Server->>Deps: install_playwright_chromium()
Deps->>OS: subprocess.run([sys.executable, "-m", "playwright", "install", "chromium"])
alt Success (returncode=0)
OS-->>Deps: stdout
else Failure (returncode!=0 or timeout)
OS-->>Deps: stderr / TimeoutExpired
Deps-->>Server: Raise RuntimeError
end
end
Server-->>Client: 200 OK (or error)
alt Success
Client-->>Hook: null
Hook->>Client: availabilityRequest.refetch()
Client->>Server: GET /api/export/availability
Server-->>Client: Updated formats (dependenciesAvailable:true)
Client-->>Hook: new ExportAvailabilityResponse
Hook-->>Dialog: Update format status (export enabled)
Dialog->>User: Export button becomes enabled, Install button hidden
else Error (HTTP 500)
Client-->>Hook: Rejects with HTTPError
Hook->>Hook: Catch error, log
Hook->>Hook: set isInstalling=false
Hook-->>Dialog: Toast: "Failed to install missing packages"
Dialog->>User: Install button re-enabled, error toast displayed
end
end
Note over Hook,Client: Guard: installAllowed check from user config
Note over Client,Server: Server install skips kernel dependency (no waitForKernelToBeInstantiated)
Add the dialog action and typed request plumbing, refresh availability after installation, and preserve manual setup guidance.
ca4c7f1 to
9b27518
Compare
|
@cubic-dev-ai review please |
@peter-gy I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
All reported issues were addressed across 16 files
Architecture diagram
sequenceDiagram
participant User
participant ExportDialog as Export Dialog
participant useExportDialog as useExportDialog Hook
participant Requests as Request Client Layer
participant Server as Server API
participant Toast as Toast Notification
Note over User,Toast: User opens export dialog for unavailable format (e.g., PDF)
ExportDialog->>useExportDialog: mount & initialize
useExportDialog->>Requests: getExportAvailability()
Requests->>Server: GET /api/export/availability
Server-->>Requests: { formats: [ { format: "pdf", dependenciesAvailable: false, missingPackages: ["nbconvert[webpdf]"] } ] }
Requests-->>useExportDialog: availability response
useExportDialog->>useExportDialog: compute canInstall (installAllowed && missing-packages|missing-setup)
useExportDialog-->>ExportDialog: status = unavailable, canInstall = true
ExportDialog->>User: render format notice with Install button
Note over User,Toast: User clicks Install button
User->>ExportDialog: click Install
ExportDialog->>useExportDialog: installRequirements()
useExportDialog->>useExportDialog: setIsInstalling(true)
useExportDialog->>ExportDialog: re-render with busy state
ExportDialog->>ExportDialog: disable all export tabs & submit button
useExportDialog->>Requests: installExportRequirements({ format: "pdf" })
alt Session not connected
Requests->>Requests: startConnectionWithoutKernel (init runtime + waitForConnectionOpen)
Note over Requests: Does NOT waitForKernelToBeInstantiated
end
Requests->>Server: POST /api/export/requirements/install { format: "pdf" }
alt Installation succeeds
Server-->>Requests: { source: "server", formats: [ { format: "pdf", dependenciesAvailable: true } ] }
Requests-->>useExportDialog: updated availability
useExportDialog->>useExportDialog: availabilityRequest.setData(availability)
useExportDialog->>Requests: getExportAvailability() (refreshes full manifest)
Requests-->>useExportDialog: fresh availability
useExportDialog->>useExportDialog: setIsInstalling(false)
useExportDialog-->>ExportDialog: status = available, canInstall = false
ExportDialog->>ExportDialog: re-enable & allow export
ExportDialog-->>User: format now ready, Install button gone
else Installation fails
Server-->>Requests: HTTP 500 { detail: "Playwright Chromium installation failed..." }
Requests-->>Toast: toast({ title: "Failed to install export requirements", description: "...", variant: "danger" })
Requests-->>useExportDialog: rejected promise
useExportDialog->>useExportDialog: setIsInstalling(false) in finally block
useExportDialog-->>ExportDialog: install button re-enabled, format still unavailable
ExportDialog-->>User: Install button clickable again, error toast visible
end
Note over ExportDialog,User: Read-only / kiosk mode (Install button hidden entirely)
alt mode=read or kioskMode or ?kiosk query param
useExportDialog->>useInstallAllowed: returns false
useExportDialog->>ExportDialog: canInstall = false
ExportDialog->>User: show setup command text (e.g., "uv run playwright install chromium") instead of Install button
end
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Match the server's exact kiosk=true contract so explicit false values keep installation available. Cover pending install locking and kernel-independent instantiation in the surrounding flow.
| getExportAvailability: () => { | ||
| return getClient().GET("/api/export/availability").then(handleResponse); | ||
| }, | ||
| installExportRequirements: (request) => { |
There was a problem hiding this comment.
is it possible to avoid another endpoint by reusing the existing install command?
| | "throwError" | ||
| | "dropRequest" | ||
| | "startConnection" | ||
| | "startConnectionWithoutKernel" |
There was a problem hiding this comment.
Should this just be waitForConnection? I may need to revisit some of this logic.
Companion of #10473.
Summary
The export dialog identifies missing requirements, but users must install them outside the web UI.
Add a compact Install action to unavailable export formats. The action calls the server-owned installation contract from #10473, refreshes availability after installation, and prevents overlapping dialog actions while the request is running. Installation failures use the existing request toast above the dialog.
Read-only and kiosk views keep the manual setup command visible.
Demo