Skip to content

UN-2946 [MISC] Restore Prompt Studio public sharing after lookups V2 wiring#1963

Merged
athul-rs merged 5 commits into
mainfrom
fix/axios-401-public-share
May 14, 2026
Merged

UN-2946 [MISC] Restore Prompt Studio public sharing after lookups V2 wiring#1963
athul-rs merged 5 commits into
mainfrom
fix/axios-401-public-share

Conversation

@chandrasekharan-zipstack
Copy link
Copy Markdown
Contributor

@chandrasekharan-zipstack chandrasekharan-zipstack commented May 13, 2026

What

Why

  • The lookups V2 PR added useLookupDirtySeed (cloud plugin) which mounts unconditionally inside ToolIde and probes /api/v1/unstract/<orgId>/prompt-studio/<toolId>/check_deployment_usage/. In the anonymous share viewer orgId is undefined and the request 401s. The global useAxiosPrivate response interceptor calls logout() on any 401, redirecting the share page through /api/v1/logout. The share viewer has no session to expire, so the interceptor was effectively bricking the page.
  • Locally, the Traefik router only forwarded /api/v1 and /deployment to the backend, so /public/share/* fell through to the Vite dev server and returned the SPA index HTML instead of JSON. Staging works only because the staging ingress already has a /public rule.
  • For anonymous viewers the enriched (post-lookup) value is the point of the project; defaulting to Raw made shared projects look empty when the LLM extraction alone wasn't meaningful.

How

  • frontend/src/hooks/useAxiosPrivate.js: gate logout() behind !window.location.pathname.startsWith("/promptStudio/share"). A 401 on the share viewer is a misrouted authenticated probe, not an expired session.
  • docker/docker-compose.yaml and docker/sample.proxy_overrides.yaml: add PathPrefix(/public) to the backend Traefik rule and exclude /public from the frontend negative-match.
  • frontend/src/components/custom-tools/combined-output/JsonView.jsx: read isPublicSource from the custom-tool store and initialize activeView to "Enriched" when true. The existing useEffect already falls back to "Raw" when no enriched data is present, so non-lookup projects are unaffected.

Can this PR break any existing features. If yes, please list possible items. If no, please explain why. (PS: Admins do not merge the PR without this section filled)

  • Low risk. Each change is scoped to the public-share viewer or to local-dev proxy routing:
    • The 401 → logout gate only short-circuits when the path starts with /promptStudio/share. Authenticated editor flows still call logout() on session expiry as before.
    • The Traefik change is local-dev only (docker-compose.yaml + sample.proxy_overrides.yaml); the staging/prod ingresses are unchanged and already route /public correctly.
    • JsonView default-tab change is gated on isPublicSource. Editor sessions still default to "Raw".

Database Migrations

  • None.

Env Config

  • None.

Relevant Docs

  • None.

Related Issues or PRs

Dependencies Versions

  • None.

Notes on Testing

  1. Pull the branch + the cloud-side companion PR; run python copy_cloud_deps.py -y from the cloud worktree into the OSS worktree.
  2. VERSION=public-share-test docker compose -f docker-compose.yaml -f compose.override.yaml build frontend backend and up -d frontend backend.
  3. As a signed-in user, create or pick a Prompt Studio project with at least one lookup-assigned prompt, then enable public sharing and copy the share URL.
  4. Open the share URL in a private/incognito window:
    • Page renders project, prompts, and outputs.
    • Network tab: no /api/v1/logout redirect.
    • Network tab: no /api/v1/unstract/undefined/prompt-studio/.../check_deployment_usage/ call.
    • /public/share/prompt-studio-metadata/, /document-metadata/, /profiles-metadata/, /outputs-metadata/ all return 200 JSON via frontend.unstract.localhost.
    • Combined Output → JSON view opens on "Enriched" for lookup-assigned prompts; "Raw" toggle still works.
  5. Sign back in and confirm the editor flow still defaults to "Raw", and that a deliberate 401 (e.g. expired session) still triggers logout.

Screenshots

N/A — behavioural fix; no UI redesign.

Checklist

I have read and understood the Contribution Guidelines.

…iring

Three issues broke /promptStudio/share/* after the lookups V2 PR:

- The global useAxiosPrivate response interceptor calls logout() on any
  401. An authenticated probe leaking into the anonymous share viewer
  (e.g. the new useLookupDirtySeed hook on first mount) returned 401 and
  redirected the share page through /api/v1/logout. Skip the logout when
  the current path is /promptStudio/share/* — the viewer has no session
  to expire.

- The local Traefik router only forwarded /api/v1 and /deployment to the
  backend; /public/share/* fell through to the Vite dev server and the
  share endpoints returned the SPA index instead of JSON. Add /public to
  the backend rule (and to the frontend negative match) in both the
  compose labels and the sample proxy override.

- The Combined Output JSON view defaulted to the Raw tab even when an
  enriched lookup output existed. For anonymous share viewers the
  enriched value is the point of the project; default activeView to
  Enriched when isPublicSource. The existing useEffect already falls
  back to Raw when no enriched data is present, so projects without
  lookups are unaffected.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 13, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1cc1f5a1-6dab-4d6e-bbac-26b913738c53

📥 Commits

Reviewing files that changed from the base of the PR and between e3a97cb and 738df18.

📒 Files selected for processing (2)
  • frontend/src/components/custom-tools/combined-output/JsonView.jsx
  • frontend/src/hooks/useAxiosPrivate.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/components/custom-tools/combined-output/JsonView.jsx

Summary by CodeRabbit

  • New Features

    • Public content sharing now auto-selects an optimized enriched view for anonymous viewers, with fallback to raw output when enriched data is unavailable.
  • Bug Fixes

    • Routing updated so public paths are correctly handled across services.
    • Session handling improved for public-share viewers to avoid unintended logouts during shared access.

Walkthrough

Traefik routing was updated to account for /public paths; the frontend 401 handler suppresses logout for public-share viewer routes; JsonView defaults to the Enriched view for public sources and falls back to Raw when enriched output is absent.

Public Content Sharing Infrastructure

Layer / File(s) Summary
Traefik routing rules (compose + overrides)
docker/docker-compose.yaml, docker/sample.proxy_overrides.yaml
docker/docker-compose.yaml: backend router rule now includes PathPrefix('/public'); frontend router rule in compose now explicitly excludes /public from the frontend catch-all. docker/sample.proxy_overrides.yaml: http.routers.frontend.rule updated to match Host(\frontend.unstract.localhost`)combined withPathPrefix('/api/v1')ORPathPrefix('/deployment')ORPathPrefix('/public')`.
Auth error handling for public-share viewers
frontend/src/hooks/useAxiosPrivate.js
401 response interceptor now detects onPublicShare via globalThis.location?.pathname.startsWith("/promptStudio/share/"). If true, the handler bypasses calling logout() (and emits a console.warn with the failing request URL and current path); otherwise it still calls logout(). The interceptor continues to return Promise.reject(error).
Client UI default view for public sources
frontend/src/components/custom-tools/combined-output/JsonView.jsx
Reads isPublicSource from useCustomToolStore. activeView initializes to "Enriched" for public sources and "Raw" for non-public. Adds effect to force "Raw" when enrichedOutput is empty and to set "Enriched" once when enrichedOutput arrives for public sources. Display logic otherwise shows enrichedOutput when active and present, falling back to combinedOutput.
sequenceDiagram
    participant Client as Client (browser)
    participant Traefik as Traefik proxy
    participant Frontend as Frontend app
    participant Backend as Backend API
    participant Auth as Auth/logout flow

    Client->>Traefik: HTTP request (e.g., /public or frontend paths)
    Traefik-->>Backend: Route to Backend when PathPrefix('/public') matches
    Traefik-->>Frontend: Route frontend requests (compose excludes /public)
    Client->>Frontend: Load public share page (/promptStudio/share/...)
    Frontend->>Backend: API request
    Backend-->>Frontend: 401 response
    Frontend->>Auth: 401 handler checks globalThis.location.pathname
    alt path starts with /promptStudio/share/
        Auth-->>Frontend: skip logout, log warning, return rejected error
    else
        Auth-->>Frontend: trigger logout flow
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly references the specific issue (UN-2946) and describes the main objective: restoring public sharing functionality after Lookups V2 changes.
Description check ✅ Passed The description comprehensively covers all required template sections with specific details about what was fixed, why it matters, how the changes work, risk assessment, testing steps, and related issues.
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/axios-401-public-share

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.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 13, 2026

Greptile Summary

This PR restores the anonymous Prompt Studio public-share viewer (/promptStudio/share/<id>) that broke after the lookups V2 PR added an unconditional authenticated probe that 401'd when orgId was undefined, triggering a global logout interceptor. The fix is three-part: gate the 401→logout on the share path, route /public/* through Traefik to the backend in local dev, and default the Combined Output JSON tab to "Enriched" for public viewers.

  • useAxiosPrivate.js: 401 responses on /promptStudio/share/ paths now emit a console.warn breadcrumb instead of calling logout(). All other routes are unaffected.
  • Docker/Traefik: PathPrefix(\/public`)added to the backend router rule and excluded from the frontend negative-match in bothdocker-compose.yamlandsample.proxy_overrides.yaml, matching the existing pattern for /api/v1and/deployment`.
  • JsonView.jsx: Reads isPublicSource from the custom-tool store; initialises activeView to "Enriched" when true, uses a didInitTab ref to fire the default only once so manual Raw toggles aren't overridden on re-renders, and resets the ref when enriched data disappears so the hydration race is handled correctly.

Confidence Score: 5/5

Safe to merge — all changes are narrowly scoped to the public-share viewer and local-dev proxy routing with no impact on authenticated editor flows or production ingress.

The 401→logout gate is guarded by an exact path prefix that only matches the share viewer; authenticated sessions call logout() as before. The Traefik change is local-dev only and mirrors the existing /api/v1//deployment pattern. The JsonView tab-default logic uses a didInitTab ref to fire once and correctly resets on empty enriched data, addressing the hydration-race concern from the previous review round. No database changes, no production config changes.

No files require special attention.

Important Files Changed

Filename Overview
frontend/src/hooks/useAxiosPrivate.js Added path-based guard to suppress 401→logout on /promptStudio/share/ routes, with a console.warn breadcrumb; logic is correct and low-risk
frontend/src/components/custom-tools/combined-output/JsonView.jsx Reads isPublicSource from store to default tab to "Enriched" for public viewers; didInitTab ref prevents re-render from stomping manual Raw toggle; hydration race addressed via useEffect deps on both enrichedOutput and isPublicSource
docker/docker-compose.yaml Adds PathPrefix(/public) to backend Traefik rule and corresponding !PathPrefix(/public) to frontend negative-match; mirrors existing pattern for /api/v1 and /deployment
docker/sample.proxy_overrides.yaml Adds /public to backend router rule; frontend catch-all relies correctly on Traefik specificity (backend rule always wins for more-specific paths)

Sequence Diagram

sequenceDiagram
    participant Browser as Anonymous Browser
    participant Frontend as Frontend (React)
    participant Traefik as Traefik Proxy
    participant Backend as Backend (Django)

    Browser->>Traefik: "GET /promptStudio/share/<id>"
    Traefik->>Frontend: (SPA catch-all)
    Frontend-->>Browser: Render PublicPromptStudioHelper

    Note over Frontend: isPublicSource = true
    Note over Frontend: JsonView defaults to Enriched

    Frontend->>Traefik: GET /public/share/prompt-studio-metadata/
    Traefik->>Backend: (PathPrefix /public → backend)
    Backend-->>Frontend: 200 JSON metadata

    Frontend->>Traefik: GET /api/v1/undefined/.../check_deployment_usage/
    Note over Frontend: useLookupDirtySeed probe — orgId undefined
    Traefik->>Backend: forwards
    Backend-->>Frontend: 401

    Note over Frontend: useAxiosPrivate interceptor
    Note over Frontend: pathname starts with /promptStudio/share/
    Note over Frontend: console.warn, skip logout()

    Frontend-->>Browser: Page remains visible, outputs shown
Loading

Reviews (6): Last reviewed commit: "UN-2946 [FIX] Address review on public-s..." | Re-trigger Greptile

Comment thread frontend/src/hooks/useAxiosPrivate.js Outdated
Comment thread frontend/src/components/custom-tools/combined-output/JsonView.jsx
chandrasekharan-zipstack and others added 2 commits May 13, 2026 18:57
Drop incident/context references; keep one-line WHYs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- useAxiosPrivate: trailing slash so the prefix doesn't match unintended
  siblings of /promptStudio/share/.
- JsonView: re-sync activeView when isPublicSource or enrichedOutput
  changes, not just on first mount, to survive store hydration order.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@chandrasekharan-zipstack chandrasekharan-zipstack changed the title UN-2946 [FIX] Restore Prompt Studio public sharing after lookups V2 wiring UN-2946 [MISC] Restore Prompt Studio public sharing after lookups V2 wiring May 13, 2026
Resolves SonarCloud S7764 findings on useAxiosPrivate.js.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@athul-rs athul-rs left a comment

Choose a reason for hiding this comment

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

Two findings I'd like resolved (or at least called out as intended) before merge. Everything else is a suggestion and can go in a follow-up.

Comment thread frontend/src/hooks/useAxiosPrivate.js
Comment thread frontend/src/components/custom-tools/combined-output/JsonView.jsx
@athul-rs athul-rs closed this May 14, 2026
@athul-rs athul-rs reopened this May 14, 2026
- Log a console.warn breadcrumb when a 401 is suppressed on the public
  share route so stray authenticated probes don't go silent.
- Gate the JsonView Enriched default behind a first-load ref so the
  default fires once and a manual Raw toggle isn't stomped on
  re-renders.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

Frontend Lint Report (Biome)

All checks passed! No linting or formatting issues found.

@sonarqubecloud
Copy link
Copy Markdown

@athul-rs athul-rs merged commit 8fdef4e into main May 14, 2026
8 checks passed
@athul-rs athul-rs deleted the fix/axios-401-public-share branch May 14, 2026 06:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants