Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

UN-3185 [FIX] Deterministic CSS cascade (single bundle) + asset gzip + Edit LLM Profile modal layout#2128

Merged
kirtimanmishrazipstack merged 8 commits into
mainZipstack/unstract:mainfrom
un-3185-css-order-fixZipstack/unstract:un-3185-css-order-fixCopy head branch name to clipboard
Jun 30, 2026
Merged

UN-3185 [FIX] Deterministic CSS cascade (single bundle) + asset gzip + Edit LLM Profile modal layout#2128
kirtimanmishrazipstack merged 8 commits into
mainZipstack/unstract:mainfrom
un-3185-css-order-fixZipstack/unstract:un-3185-css-order-fixCopy head branch name to clipboard

Conversation

@chandrasekharan-zipstack

Copy link
Copy Markdown
Contributor

What

Frontend fixes under UN-3185 (lazy-loading follow-ups), all in frontend/:

  • Deterministic CSS cascade — render all CSS into a single bundle (cssCodeSplit: false) instead of per-route chunks.
  • Compress static assetsgzip_types + gzip_proxied any in nginx.conf so JS/CSS/fonts gzip on the wire.
  • Edit LLM Profile modal layout — drop the #2119 scroll-context workaround, scope the content padding, and remove the inner scrollbar.

Why

  • After UN-3185: Defer heavy chunks on login route + cache fingerprinted assets #2114 split route pages into React.lazy chunks, each route's CSS loads as a separate file at navigation time. Equal-specificity rules across components then resolve in load order, which is non-deterministic — breaking the Edit LLM Profile form and overlapping the Execution Logs table header onto the summary cards. Merging CSS into one bundle restores the deterministic order that existed before the split (JS code-splitting — the actual perf win — is unaffected).
  • nginx had gzip on but no gzip_types, so only text/html compressed; and gzip_proxied defaults to off, so even with types listed nothing compressed behind the GKE load balancer (every request carries a Via header). Assets shipped uncompressed (~341 KB CSS). This offsets the single-bundle's upfront cost and speeds every asset.
  • The Edit LLM Profile modal showed an unnecessary inner scrollbar: the settings row is hard-fixed at 800px, forcing the form's column (.conn-modal-col) to scroll once Advanced Settings expands.

How

  • vite.config.js: build.cssCodeSplit: false.
  • nginx.conf: add gzip_types (css/js/json/svg/fonts), gzip_min_length, gzip_vary on, gzip_proxied any.
  • AddLlmProfile.jsx/.css: replace the form root's shared settings-body-pad-top/add-llm-profile-scroll-root classes with a single add-llm-profile-body marker; drop the dead overflow: visible override; scope the content padding via :has(); and let the settings row size to the form (:has(.add-llm-profile-body) { height: auto !important }) so the modal grows instead of nesting a scrollbar.

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)

No.

  • The modal changes are scoped via :has(.add-llm-profile-body), which matches only the Edit LLM Profile form. The shared .conn-modal-row / .conn-modal-col / .conn-modal-form-pad-left classes are still used by the other Prompt Studio settings panels and by ConfigureConnectorModal (the connector dialog) — none of those carry the marker, so they are untouched. No shared CSS rule was deleted (the classes are still in use, i.e. not unused).
  • cssCodeSplit: false and the nginx gzip settings are build/serving config; no application behaviour changes.

Notes on Testing

  • Built and deployed to the chandru-unstract-dev namespace (staging). Verified on chandru.globe.unstract.com: a single /assets/*.css bundle; assets served content-encoding: gzip (CSS 341 KB → 78 KB on the wire); the scoped :has rules present in the served bundle.

Related Issues or PRs

Checklist

I have read and understood the Contribution Guidelines.

chandrasekharan-zipstack and others added 5 commits June 30, 2026 10:38
…order

Code-splitting (#2114) injects per-route CSS at navigation time, so
equal-specificity rules across components resolve in load order — breaking
the Edit LLM Profile form and Execution Logs header layout (UN-3185).
cssCodeSplit:false restores a single deterministic stylesheet; JS splitting
is unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015DsoHbMN7kTTWwcVC6NNkg
nginx `gzip on` only compresses text/html by default, so JS/CSS shipped
uncompressed. Add gzip_types so the single CSS bundle (~341KB -> ~57KB) and
all JS chunks compress on the wire — offsets the cssCodeSplit:false upfront
cost and speeds every asset.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015DsoHbMN7kTTWwcVC6NNkg
…roll classes

Remove settings-body-pad-top + add-llm-profile-scroll-root from the form root
(the shared overflow-y:auto added a nested scroll context that #2119 only
patched over). The sticky footer now pins directly to .conn-modal-col. Replace
the dead override with a :has()-scoped padding so .conn-modal-form-pad-left is
adjusted for this panel alone — sibling settings panels and the connector
dialog are untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015DsoHbMN7kTTWwcVC6NNkg
nginx skips gzip for proxied requests by default (gzip_proxied off); the GKE
load balancer adds a Via header to every request, so static assets shipped
uncompressed despite gzip_types. Verified gzip works direct-to-pod.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015DsoHbMN7kTTWwcVC6NNkg
The settings row is hard-fixed at 800px, forcing the form's column
(.conn-modal-col) to scroll once Advanced Settings expands. Let the row size to
the form so the modal grows instead. Scoped via :has to the LLM profile panel —
the other settings panels and the connector dialog share .conn-modal-row/-col
and are untouched (so the shared class stays; it is not unused).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015DsoHbMN7kTTWwcVC6NNkg
@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

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: 999d737b-0b0c-48a8-92de-6f4a41410607

📥 Commits

Reviewing files that changed from the base of the PR and between 86cd5a4 and 156ceec.

📒 Files selected for processing (1)
  • frontend/nginx.conf
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/nginx.conf

Summary by CodeRabbit

  • Bug Fixes

    • Fixed the add LLM profile modal layout so the form expands naturally while keeping the footer visible (avoids conflicting scroll behavior).
    • Enhanced gzip compression for common web assets, including CSS/JS/JSON and SVG, with tuned gzip settings to reduce transfer size.
  • Build / Configuration

    • Improved stylesheet loading consistency by disabling CSS code splitting in the Vite build.

Walkthrough

Vite build config disables CSS code splitting. The AddLlmProfile modal wrapper and styles change to use add-llm-profile-body with :has()-scoped padding and overflow rules. nginx adds explicit gzip type, size, vary, and proxy settings.

Changes

Frontend build and UI layout

Layer / File(s) Summary
Vite CSS chunking
frontend/vite.config.js
Adds build.cssCodeSplit: false with explanatory comments.
AddLlmProfile modal layout
frontend/src/components/custom-tools/add-llm-profile/AddLlmProfile.jsx, frontend/src/components/custom-tools/add-llm-profile/AddLlmProfile.css
Replaces the wrapper class with add-llm-profile-body and updates modal CSS with :has()-scoped padding, height, and overflow overrides.
nginx gzip settings
frontend/nginx.conf
Adds gzip_types, gzip_min_length 1024, gzip_vary on, and gzip_proxied any in the http block.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 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 Clear and specific summary of the main frontend changes: CSS bundling, gzip, and modal layout.
Description check ✅ Passed Most required sections are present and filled, though several template sections are left empty or sparse.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch un-3185-css-order-fix

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.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015DsoHbMN7kTTWwcVC6NNkg
@chandrasekharan-zipstack chandrasekharan-zipstack marked this pull request as ready for review June 30, 2026 06:43
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015DsoHbMN7kTTWwcVC6NNkg
@greptile-apps

greptile-apps Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes three frontend issues introduced after lazy-loading was enabled in #2114: non-deterministic CSS cascade order (fixed by merging all CSS into a single bundle via cssCodeSplit: false), uncompressed static assets behind the GKE load balancer (fixed by adding gzip_types, gzip_min_length, gzip_vary, and gzip_proxied any to nginx.conf), and an unnecessary inner scrollbar on the Edit LLM Profile modal (fixed by scoping height/overflow overrides with :has(.add-llm-profile-body) selectors).

  • vite.config.js: cssCodeSplit: false collapses all CSS into one deterministic bundle; JS chunk splitting is untouched.
  • nginx.conf: Enables gzip for CSS/JS/JSON/SVG and sets gzip_proxied any so the GKE Via header no longer prevents compression.
  • AddLlmProfile.css/.jsx: Replaces dual class markers with a single add-llm-profile-body anchor; :has() selectors scope the layout fix to only this modal without touching shared classes used elsewhere.

Confidence Score: 4/5

Safe to merge with one fix recommended: the gzip_types entry for JavaScript should include text/javascript to cover nginx 1.23.0+.

The gzip_types directive lists only application/javascript, but nginx 1.23.0+ ships with text/javascript in its mime.types for .js files. If the deployed image is on a recent nginx, JavaScript assets will be served uncompressed — silently, with no error — which partially defeats the compression goal of this PR.

frontend/nginx.conf — specifically the gzip_types line and whether application/javascript matches the MIME type the running nginx image uses for .js files.

Important Files Changed

Filename Overview
frontend/nginx.conf Adds gzip compression for CSS/JS/JSON/SVG assets and enables gzip_proxied any for GKE LB. Uses application/javascript which may not match in newer nginx images that serve JS as text/javascript per RFC 9239.
frontend/src/components/custom-tools/add-llm-profile/AddLlmProfile.css Replaces the old overflow workaround with scoped :has() selectors to fix the inner scrollbar on the Edit LLM Profile modal; sticky footer rule is preserved.
frontend/src/components/custom-tools/add-llm-profile/AddLlmProfile.jsx Replaces dual class markers with a single add-llm-profile-body class; a straightforward, minimal JSX change.
frontend/vite.config.js Adds cssCodeSplit: false to merge all CSS into a single deterministic bundle; JS code splitting is unaffected.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Browser requests page] --> B[GKE Load Balancer adds Via header]
    B --> C[nginx]
    C --> D{Asset type?}
    D -->|assets css| E[Single CSS bundle - cssCodeSplit false - deterministic cascade]
    D -->|assets js| F[JS chunks - manualChunks preserved]
    D -->|index.html| G[SPA entry - no-cache]
    E --> H{gzip_proxied any enabled?}
    F --> H
    H -->|Yes - Via header no longer skips| I[Compress - content-encoding gzip]
    H -->|No - old gzip_proxied off| J[Uncompressed - old behaviour]
    I --> K[Browser renders app]
    G --> K

    style E fill:#d4edda,stroke:#28a745
    style I fill:#d4edda,stroke:#28a745
    style J fill:#f8d7da,stroke:#dc3545
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[Browser requests page] --> B[GKE Load Balancer adds Via header]
    B --> C[nginx]
    C --> D{Asset type?}
    D -->|assets css| E[Single CSS bundle - cssCodeSplit false - deterministic cascade]
    D -->|assets js| F[JS chunks - manualChunks preserved]
    D -->|index.html| G[SPA entry - no-cache]
    E --> H{gzip_proxied any enabled?}
    F --> H
    H -->|Yes - Via header no longer skips| I[Compress - content-encoding gzip]
    H -->|No - old gzip_proxied off| J[Uncompressed - old behaviour]
    I --> K[Browser renders app]
    G --> K

    style E fill:#d4edda,stroke:#28a745
    style I fill:#d4edda,stroke:#28a745
    style J fill:#f8d7da,stroke:#dc3545
Loading

Reviews (2): Last reviewed commit: "fix: drop pre-compressed font types from..." | Re-trigger Greptile

Comment thread frontend/nginx.conf Outdated
WOFF2 (Brotli) and WOFF (zlib) are already compressed; re-gzipping wastes
CPU for no size gain. application/font-woff also never matches nginx's
mime.types (.woff -> font/woff), so it was a no-op.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015DsoHbMN7kTTWwcVC6NNkg
@github-actions

Copy link
Copy Markdown
Contributor

Frontend Lint Report (Biome)

All checks passed! No linting or formatting issues found.

@kirtimanmishrazipstack kirtimanmishrazipstack merged commit cc952bf into main Jun 30, 2026
9 checks passed
@kirtimanmishrazipstack kirtimanmishrazipstack deleted the un-3185-css-order-fix branch June 30, 2026 07:17
@sonarqubecloud

Copy link
Copy Markdown

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.

2 participants

Morty Proxy This is a proxified and sanitized view of the page, visit original site.