Skip to content

feat(export): install requirements from dialog - #10471

Open
peter-gy wants to merge 2 commits into
marimo-team:ptr/install-export-requirementsfrom
peter-gy:ptr/install-deps-from-export-dialog
Open

feat(export): install requirements from dialog#10471
peter-gy wants to merge 2 commits into
marimo-team:ptr/install-export-requirementsfrom
peter-gy:ptr/install-deps-from-export-dialog

Conversation

@peter-gy

@peter-gy peter-gy commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

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

export-rebase-install-error-settled

Copilot AI review requested due to automatic review settings August 6, 2026 07:32
@vercel

vercel Bot commented Aug 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
marimo-docs Ready Ready Preview Aug 6, 2026 12:42pm

Request Review

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions github-actions Bot added the bash-focus Area to focus on during release bug bash label Aug 6, 2026
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Loading

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread frontend/src/components/editor/actions/export-dialog/use-export-dialog.ts Outdated
Comment thread frontend/src/components/editor/actions/export-dialog/format-notice.tsx Outdated
Comment thread marimo/_export/dependencies.py Outdated
Comment thread frontend/src/components/editor/actions/export-dialog/format-notice.tsx Outdated
@peter-gy

peter-gy commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review please

@cubic-dev-ai

cubic-dev-ai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review please

@peter-gy I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)
Loading

Re-trigger cubic

@peter-gy
peter-gy marked this pull request as draft August 6, 2026 09:46
Add the dialog action and typed request plumbing, refresh availability after installation, and preserve manual setup guidance.
@peter-gy
peter-gy force-pushed the ptr/install-deps-from-export-dialog branch from ca4c7f1 to 9b27518 Compare August 6, 2026 12:01
@peter-gy
peter-gy changed the base branch from main to ptr/install-export-requirements August 6, 2026 12:03
@peter-gy peter-gy changed the title feat: install export requirements from dialog feat(export): install requirements from dialog Aug 6, 2026
@peter-gy

peter-gy commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review please

@cubic-dev-ai

cubic-dev-ai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review please

@peter-gy I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Loading

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread frontend/src/core/mode.ts Outdated
Comment thread frontend/src/core/network/requests-lazy.ts
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.
@peter-gy
peter-gy marked this pull request as ready for review August 6, 2026 12:45
@peter-gy
peter-gy requested a review from mscolnick August 6, 2026 12:45
getExportAvailability: () => {
return getClient().GET("/api/export/availability").then(handleResponse);
},
installExportRequirements: (request) => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it possible to avoid another endpoint by reusing the existing install command?

| "throwError"
| "dropRequest"
| "startConnection"
| "startConnectionWithoutKernel"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this just be waitForConnection? I may need to revisit some of this logic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bash-focus Area to focus on during release bug bash enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants