From f44f97a114355b8f03ad912d973966bd637f3116 Mon Sep 17 00:00:00 2001 From: Pierre Jeambrun Date: Sat, 23 May 2026 00:42:49 +0200 Subject: [PATCH] [v3-2-test] UI: Fix Expand/Collapse All on XComs and Audit Log JSON cells (#67316) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * UI: Fix Expand/Collapse All on XComs and Audit Log JSON cells The Expand/Collapse All toggle on the XComs and Audit Log pages was no-op: clicking the buttons updated the toggle state but the JSON content in each row stayed in its initial fold state. `RenderedJsonField` runs Monaco's `editor.foldAll` action in `handleMount` based on the initial `collapsed` prop, but never reacts to subsequent changes to that prop. Save a ref to the editor instance and add a `useEffect` that runs `editor.foldAll`/`editor.unfoldAll` whenever `collapsed` changes after mount. * UI: Register Monaco folding contribution so foldAll/unfoldAll actions exist The previous useEffect in RenderedJsonField calls `editor.foldAll` / `editor.unfoldAll` to react to `collapsed` prop changes, but #66647 switched Monaco from the CDN bundle to a local `editor.api` import that does not register any editor contributions. As a result those actions do not exist, `editor.getAction(...)` returns null, and the toggle does nothing. Side-effect-import the folding contribution alongside `editor.api` to register the FoldingController and its `editor.foldAll` / `editor.unfoldAll` actions — the minimum needed for the expand/collapse toggle to work. Other contributions are intentionally left out to keep this change focused on the bug. * UI: Unblock RenderedJsonField visibility from the foldAll promise `editor.foldAll` awaits the FoldingModel, which in turn waits for fold ranges from the JSON syntax provider. When the JSON worker is unavailable (common in proxied dev setups where Vite's worker URLs do not resolve) that promise can stay pending forever, leaving `isReady` false and the parent Flex wrapper collapsed to `height: 0px; overflow: hidden` — which makes the editor completely invisible. Fire the foldAll action and set `isReady` immediately rather than gating it on the promise. The folded layout still settles via `onDidContentSizeChange` once Monaco computes it; this just removes the hard dependency on a promise that may never resolve. * UI: Set Vite server.origin so dev-mode worker URLs are absolute In dev mode the SPA shell is served by the airflow api-server on a different origin than Vite. Without `server.origin`, Vite emits asset URLs as absolute paths (e.g. `/node_modules/.../json.worker.js?worker_file`) which the browser resolves against the page origin — the api-server, which serves the SPA fallback HTML for unknown paths. The Monaco workers therefore fail to load (text/html MIME), and the JSON fold-range provider's promise stays pending, which is what made the editor stay unfolded on collapse in dev mode. Pinning `server.origin` to localhost:5173 (matching the `--strictPort` on the dev script) makes Vite emit fully-qualified URLs so workers load from Vite directly, regardless of the page origin. * Revert "UI: Unblock RenderedJsonField visibility from the foldAll promise" This reverts commit 8c2439fa1fb29f4902f3968ef1e3a13009c2864a. * UI: Load codicon styles so the fold gutter glyph renders The Monaco folding contribution renders the per-line expand/collapse indicator (the `>` arrow next to a foldable region) by placing a `codicon codicon-folding-collapsed` / `codicon-folding-expanded` span in the gutter. Without the codicon CSS (which defines the @font-face and maps the class names to glyph characters) the span renders as an empty square. The CDN bundle pulled in `codiconStyles` transitively via `editor.all`; the local ESM `editor.api` entry point does not. Import it explicitly alongside the folding contribution. * UI: Inject codicon font face with a Vite-resolved URL Importing `codiconStyles` (which transitively imports `codicon.css`) broke the production build through `vite-plugin-css-injected-by-js`: - the inlined `@font-face { src: url(./codicon.ttf) }` rule resolved the relative URL against the page origin (the airflow api-server) instead of `/static/assets/`, so the font fetch fell back to the SPA HTML and Chrome reported 'OTS parsing error'; - the plugin removes the emitted CSS chunk but the JS bundle still contained a phantom `modulepreload` for it, which 404'd and rejected the `configureMonaco` promise — `isReady` never flipped and the editor never mounted. Inject the @font-face + base `.codicon` class ourselves, using Vite's `?url` import to resolve the font asset path. Monaco still registers the per-icon `::before` content rules at runtime via its theme service, so that is the only piece of the static codicon CSS we need. * Revert "UI: Inject codicon font face with a Vite-resolved URL" This reverts commit 9b6fc3f6caf56c91f6773e292bde8da8eed21121. * UI: Keep Monaco codicon CSS as an emitted file Rather than hand-injecting an @font-face with a manually resolved URL, exclude the codicon CSS from vite-plugin-css-injected-by-js. The plugin inlining the stylesheet was what broke the relative font URL in the first place (the CSS ended up inside a