Skip to content

feat(frontend): attachment transport, references, and rendering for the agent chat - #5619

Merged
mmabrouk merged 9 commits into
release/v0.107.0from
wp4-frontend-transport
Aug 1, 2026
Merged

feat(frontend): attachment transport, references, and rendering for the agent chat#5619
mmabrouk merged 9 commits into
release/v0.107.0from
wp4-frontend-transport

Conversation

@mmabrouk

@mmabrouk mmabrouk commented Jul 31, 2026

Copy link
Copy Markdown
Member

The composer collects files but has no transport: every attachment inlines as a base64 data URL, bloats browser storage and the wire, disappears from reloaded sessions, and the person never learns whether the model actually saw it. This is work package 4 of 4 of the Stage 1 plan, the producer the reader-first rollout saved for last, stacked on the SDK package #5617.

Before: attach inlines base64; a reloaded session loses user attachments; no upload progress, no retry, no honest errors; nothing tells the user a file went workspace-only.
After: attaching uploads once through POST /sessions/attachments (progress, abort on chip removal, retry reusing the same idempotency key, send blocked with a tooltip until every upload settles) and the message carries a reference: the content URL in the part plus {attachmentId, size} in providerMetadata.agenta, never base64. Upload errors are told apart (cap, invalid file, session quota, in-flight with Retry-After, old-backend 404). Sent and reloaded conversations render through the content route with an authenticated blob fallback and no eager downloads; durable records rebuild user file parts with filenames; attachment_delivery events are parsed and persisted but render nothing (the product owner removed both notice surfaces; a future surface can render the persisted events without wire changes). The per-turn attachment count is 100 (raised from the dark-shipped 5 at the product owner's direction; the per-session quotas are the real bound). Voice recordings use references only when the uploads flag is on and keep their inline path otherwise, so the two flags stay independent.

Adversarially reviewed before opening: fourteen findings, four merge blockers, all fixed. The blockers were exactly the quiet kind: the acceptance Playwright spec sat one directory outside the collected test root (it now lives with its siblings, tagged, no silent skip); voice messages would have broken whenever uploads were off; size sat top-level where the AI SDK's validation strips it; and a hardcoded perception map contradicted the capability data computed ten lines away. Full trail in protocols/stage-1.md.

Implicit decisions and their tradeoffs

  • The shared composer package changed (RichChatInput, SubmitPlugin, SendButton gain send-only disabling). The review enumerated all three consumers; the new props default to today's behavior, so the other two surfaces are untouched.
  • The tray uid doubles as the idempotency key (one comment states it): that identity is what makes retry safe, and generateId() is used over crypto.randomUUID because dev boxes are reached over plain HTTP where the latter is undefined.
  • Static limits stay (DEFAULT_ATTACHMENT_LIMITS): capability-derived limits are a Stage 2 item.
  • web/oss joins the unit-test loop with an explicit include list (the 13 pre-existing orphaned test files stay excluded, tracked in (chore) 13 unit test files in web/oss are never run by any test runner #5618). The junit reporter is wired; the one-line CI glob addition for its report is left uncommitted because the push credential lacks the workflow scope; it is a follow-up line for a push with that scope.

Forced routes to double-check

  • Axios, not Fern, for upload and blob read: the documented exception (Fern's fetch cannot report upload progress; Fern JSON-parses binary), with zod at the boundary. The OpenAPI/Fern regeneration for typed accessors elsewhere in the domain is a stated follow-up.
  • Legacy base64 history keeps its old render path: only newly sent files use references; old conversations change nothing.

QA

lint clean, typecheck clean, 34 unit tests green with junit output. The full end-to-end live QA ran on the dev stack with all four packages deployed (full record in protocols/stage-1.md):

  • Reference upload + perception: the upload POST returns 200 with a real multipart body, the run request carries the reference (providerMetadata.agenta.attachmentId, zero base64 in 2.3 KB of body), and the model reads the image's text verbatim.
  • ZIP workspace-only: the run completes and the agent reads the archive's marker from its workspace. (Both notice surfaces that existed at QA time, the in-message line and the chip hint, were removed afterward at the product owner's direction; the first release ships no notice UI, and the persisted delivery events await a future surface.)
  • Reload from records: real filenames, reference URLs, no data: nodes in the DOM, follow-up questions answered from the re-delivered content.
  • Errors: the over-cap message names the file, its size, and the limit, with no retry offer; chip removal aborts the request.
  • The first E2E round caught one blocker this suite had missed: the shared axios instance JSON-serializes FormData unless the multipart header is explicit (the file collapsed to {} and every upload 422'd). Fixed in this diff with a comment stating the trap.

https://claude.ai/code/session_01A1XQVjHPYJgVBHWSNUphtx

@mmabrouk

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@vercel

vercel Bot commented Jul 31, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
agenta-documentation Ready Ready Preview Aug 1, 2026 6:00pm

Request Review

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added agent chat file uploads with progress tracking, cancellation, retries, and clear failure states.
    • Added support for additional file types, up to 100 attachments per message and 10 MB per unclassified file.
    • Attachments now remain available after sending and page reloads, with authenticated media loading.
    • Prevented duplicate submissions while an upload or send is in progress, with explanatory send-button feedback.
  • Bug Fixes

    • Improved attachment validation, metadata handling, and media fallback behavior.
  • Tests

    • Added unit and end-to-end coverage for upload, retry, persistence, and rendering workflows.

Walkthrough

Changes

Agent attachment flow

Layer / File(s) Summary
Attachment contracts and upload lifecycle
web/oss/src/components/AgentChatSlice/assets/*, web/oss/src/components/AgentChatSlice/hooks/useAttachmentUploads.*
Adds attachment classification, multipart uploads, response validation, retry handling, cancellation, metadata conversion, and in-flight submission guards.
Conversation upload and submission integration
hosting/docker-compose/..., web/oss/src/components/AgentChatSlice/AgentConversation.tsx, web/oss/src/components/AgentChatSlice/components/*, web/packages/agenta-ui/src/RichChatInput/*
Separates upload and voice gating, manages staged files, blocks invalid submissions, and exposes retry-aware composer controls.
Attachment replay and message rendering
web/oss/src/components/AgentChatSlice/assets/attachmentMedia.ts, web/oss/src/components/AgentChatSlice/assets/transcriptToMessages.*, web/oss/src/components/AgentChatSlice/components/AgentMessage.tsx
Reconstructs session-scoped attachment parts and renders media through direct URLs with authenticated blob fallback.
Validation and workflow records
web/oss/vitest.config.ts, web/oss/tests/playwright/..., web/oss/test-results/junit.xml, docs/design/agent-workflows/...
Adds unit and acceptance coverage and records QA, review findings, and Stage 1 status changes.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant AgentConversation
  participant AttachmentAPI
  participant AgentMessage
  participant SessionContentAPI
  User->>AgentConversation: stage and submit attachment
  AgentConversation->>AttachmentAPI: upload multipart attachment
  AttachmentAPI-->>AgentConversation: attachment metadata
  AgentConversation->>AgentMessage: render session-scoped file part
  AgentMessage->>SessionContentAPI: fetch attachment content
  SessionContentAPI-->>AgentMessage: authenticated media blob
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 71.43% which is sufficient. The required threshold is 60.00%.
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.
Title check ✅ Passed The title clearly summarizes the main changes: attachment transport, references, and rendering for agent chat.
Description check ✅ Passed The description directly explains the attachment upload, reference, rendering, retry, error-handling, and QA changes in the pull request.
✨ 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 wp4-frontend-transport

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.

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Railway Preview Environment

Status Destroyed (PR closed)

Updated at 2026-08-01T18:15:23.131Z

Comment thread web/oss/src/components/AgentChatSlice/AgentConversation.tsx Outdated
Comment thread web/oss/src/components/AgentChatSlice/assets/attachments.ts
Comment thread web/oss/src/components/AgentChatSlice/AgentConversation.tsx Outdated
@mmabrouk

mmabrouk commented Aug 1, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (6)
web/oss/vitest.config.ts (2)

14-21: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider a glob instead of a hard-coded file list.

test.include lists six specific test files. A new *.test.ts file added under AgentChatSlice will not run under pnpm test:unit unless someone remembers to add it to this list.

Use a glob such as "src/components/AgentChatSlice/**/*.test.ts" to pick up new test files automatically.

♻️ Proposed refactor to use a glob pattern
         include: [
-            "src/components/AgentChatSlice/assets/attachments.test.ts",
-            "src/components/AgentChatSlice/assets/attachmentTransport.test.ts",
-            "src/components/AgentChatSlice/assets/files.test.ts",
-            "src/components/AgentChatSlice/assets/inFlightSubmit.test.ts",
-            "src/components/AgentChatSlice/assets/transcriptToMessages.test.ts",
-            "src/components/AgentChatSlice/hooks/useAttachmentUploads.test.ts",
+            "src/components/AgentChatSlice/**/*.test.ts",
         ],

5-13: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Keep test.include patterned to include new AgentChatSlice tests.

This hard-coded list now covers six files; a new *.{test,spec}.{ts,tsx} file added under this component will not run unless it is manually appended here. Use a glob such as "src/components/AgentChatSlice/**/*.{test,spec}.{ts,tsx}" so new tests are included automatically.

web/oss/src/components/AgentChatSlice/hooks/useAttachmentUploads.test.ts (1)

1-27: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Add coverage for the hook's stateful upload lifecycle.

This file tests only removeUploadFile and isUploadRetryReady. The hook's run, retry, enqueue, and the remount-resume effect in useAttachmentUploads.ts carry the real complexity (controller replacement, retry-timer scheduling, and resume-on-remount), but none of that is exercised here.

Add renderHook-based tests for:

  • A successful upload transitioning a file from uploading to done.
  • A failed upload with retryAfterSeconds blocking retry until the deadline, then auto-running.
  • abort cancelling an in-flight upload and clearing its retry timer.
  • The remount-resume effect requeuing a file left in uploading status with no live controller.

Do you want help drafting these tests?

web/oss/src/components/AgentChatSlice/AgentConversation.tsx (1)

1945-1956: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Give the extra-file uploads an abortable controller.

Each extra upload receives the signal of a discarded AbortController, so nothing can cancel it. The conversation can unmount (session switch, pane close) while the voice clip is still uploading, and the request continues. The staged-file path avoids this: useAttachmentUploads keeps a controller per uid and aborts all of them on unmount.

Consider staging the extra entries through setFiles plus uploads.enqueue so extras share the abort, progress, and retry handling of the tray, or keep a component-scoped controller for these direct uploads.

web/oss/src/components/AgentChatSlice/components/AgentMessage.tsx (1)

261-275: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Download through the shared axios helper instead of raw fetch.

fetch(src, {credentials: "include"}) sends cookies only. The attachment endpoint is called everywhere else through the shared axios instance, which attaches the app's auth headers (see fetchAttachmentBlob in web/oss/src/components/AgentChatSlice/assets/attachmentMedia.ts). So this direct request fails on every deployment that authenticates by header, and each download pays a failed round trip before the fallback state machine starts.

Call fetchAttachmentBlob({sessionId, attachmentId}) directly here. The handler then needs no source.onError() mode switch and no fallbackDownloadPending effect, which also removes the state coupling at lines 251-259.

web/oss/src/components/AgentChatSlice/assets/attachmentMedia.ts (1)

48-63: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove the unused useAttachmentObjectUrl hook.

useAttachmentMediaSrc already handles the blob object URL case, and no tracked file imports or calls useAttachmentObjectUrl.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6d160b74-1259-42a5-bbd8-948376474ff7

📥 Commits

Reviewing files that changed from the base of the PR and between df5321b and 927cb78.

⛔ Files ignored due to path filters (1)
  • web/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (28)
  • docs/design/agent-workflows/projects/agent-multi-modality/protocols/stage-1.md
  • docs/design/agent-workflows/projects/agent-multi-modality/status.md
  • hosting/docker-compose/oss/env.oss.dev.example
  • web/oss/package.json
  • web/oss/src/components/AgentChatSlice/AgentConversation.tsx
  • web/oss/src/components/AgentChatSlice/assets/attachmentMedia.ts
  • web/oss/src/components/AgentChatSlice/assets/attachmentTransport.test.ts
  • web/oss/src/components/AgentChatSlice/assets/attachmentTransport.ts
  • web/oss/src/components/AgentChatSlice/assets/attachments.test.ts
  • web/oss/src/components/AgentChatSlice/assets/attachments.ts
  • web/oss/src/components/AgentChatSlice/assets/constants.ts
  • web/oss/src/components/AgentChatSlice/assets/files.test.ts
  • web/oss/src/components/AgentChatSlice/assets/files.ts
  • web/oss/src/components/AgentChatSlice/assets/inFlightSubmit.test.ts
  • web/oss/src/components/AgentChatSlice/assets/inFlightSubmit.ts
  • web/oss/src/components/AgentChatSlice/assets/transcriptToMessages.test.ts
  • web/oss/src/components/AgentChatSlice/assets/transcriptToMessages.ts
  • web/oss/src/components/AgentChatSlice/components/AgentMessage.tsx
  • web/oss/src/components/AgentChatSlice/components/AudioPlayer.tsx
  • web/oss/src/components/AgentChatSlice/components/ComposerAttachments.tsx
  • web/oss/src/components/AgentChatSlice/hooks/useAttachmentUploads.test.ts
  • web/oss/src/components/AgentChatSlice/hooks/useAttachmentUploads.ts
  • web/oss/test-results/junit.xml
  • web/oss/tests/playwright/acceptance/agent-chat/attach-send-render-reload.spec.ts
  • web/oss/vitest.config.ts
  • web/packages/agenta-ui/src/RichChatInput/RichChatInput.tsx
  • web/packages/agenta-ui/src/RichChatInput/plugins/SendButton.tsx
  • web/packages/agenta-ui/src/RichChatInput/plugins/SubmitPlugin.tsx

Comment on lines +396 to +404
1. **The in-message delivery notice was removed** ("<filename>: the model did not perceive this
file. The agent can use it at attachments/…"). Its wording and placement were
implementation-invented.
2. **The chip-level hint was removed too** (the crossed-eye indicator with "The model may not
perceive this file…"). The first release therefore ships no notice UI at all; decision D6's
"visible notice" is deferred to a future surface the product owner designs. The
`attachment_delivery` events keep flowing and persisting unchanged, and the front end parses
and ignores them, so that future surface needs no wire changes. The upload error messages
were reviewed and kept.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Synchronize the notice behavior in status.md.

This section states that the first release ships no notice UI. However, status.md still describes a visible notice at Line [19]–[20] and repeats the D6 notice at Line [52]–[60]. Update those statements before merging so the release records define one user-visible behavior.

Comment on lines +41 to +42
| 0 | Close the silent-failure gap: gate the ungated paste and drag path on `NEXT_PUBLIC_AGENT_FILE_UPLOADS` | in review (PR #5604) |
| 1 | First user-visible release: the attachment resource and storage, the record-schema extension, the runner's resolve-materialize-and-deliver seam for images, structured capability errors, the minimum security and limits work (per the settled matrix in [design.md](design.md), including the gateway raise to 32 MB), and the front-end transport and reference wiring | in review as four stacked PRs (#5607 API, #5615 runner, #5617 SDK, #5619 front end), end-to-end QA green on the dev stack; the trail is in [protocols/stage-1.md](protocols/stage-1.md) |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Synchronize the opening status with the stage tracker.

The file still says that implementation is the next step and that the backend has not started. The tracker now says Stage 1 is in review with end-to-end QA complete. Update the stale opening text so this page has one current lifecycle state.

Comment on lines +76 to +81
- Review and merge the Stage 1 train bottom-up (#5604, #5607, #5598, #5615, #5597, #5617,
#5619), then flip `NEXT_PUBLIC_AGENT_FILE_UPLOADS` in production as the rollout's fifth act.
- Follow-ups recorded in [protocols/stage-1.md](protocols/stage-1.md): the CI report glob line
(needs a workflow-scoped push), the Fern client regeneration, and the zip-container
classifier refinement.
- Then Stage 2 of [plan.md](plan.md).

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove the unrelated PR from the Stage 1 merge sequence.

protocols/stage-1.md records PR #5598 as pre-existing and unrelated at Line [388]–[390], but this checklist includes it in the Stage 1 train. Remove it or document the attachment dependency before using this list as the release sequence.

Comment on lines +56 to +61
const url = useMemo(() => (blob ? URL.createObjectURL(blob) : null), [blob])
useEffect(() => {
return () => {
if (url) URL.revokeObjectURL(url)
}
}, [url])

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Create the object URL in an effect, not in useMemo.

useMemo is not a guaranteed cache, and its result is not tied to the effect lifecycle. Two consequences apply here, and to the identical pattern at lines 85-90:

  • Under React StrictMode the effect runs mount → unmount → mount. The cleanup revokes the URL, then the second mount re-registers cleanup for the same memoized string. The src then points at a revoked URL and the media fails to load.
  • If React drops the memoized value without the effect running, the created URL is never revoked.

Derive the URL inside the effect and keep it in state instead.

♻️ Proposed refactor
-    const url = useMemo(() => (blob ? URL.createObjectURL(blob) : null), [blob])
-    useEffect(() => {
-        return () => {
-            if (url) URL.revokeObjectURL(url)
-        }
-    }, [url])
+    const [url, setUrl] = useState<string | null>(null)
+    useEffect(() => {
+        if (!blob) {
+            setUrl(null)
+            return
+        }
+        const next = URL.createObjectURL(blob)
+        setUrl(next)
+        return () => {
+            setUrl(null)
+            URL.revokeObjectURL(next)
+        }
+    }, [blob])
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const url = useMemo(() => (blob ? URL.createObjectURL(blob) : null), [blob])
useEffect(() => {
return () => {
if (url) URL.revokeObjectURL(url)
}
}, [url])
const [url, setUrl] = useState<string | null>(null)
useEffect(() => {
if (!blob) {
setUrl(null)
return
}
const next = URL.createObjectURL(blob)
setUrl(next)
return () => {
setUrl(null)
URL.revokeObjectURL(next)
}
}, [blob])

…he agent chat

Attaching a file now uploads it once through the create route (axios with
progress, the documented Fern exception; the tray uid doubles as the
idempotency key so retry reuses the original identity) and the outgoing
message carries a reference: the real content URL in the part's url and
{attachmentId, size} in providerMetadata.agenta, never base64. Upload errors
are told apart (cap 413, invalid 422, quota 429, in-flight 409 honoring
Retry-After, old-backend 404); removing a chip aborts its request; send blocks
with a tooltip until every upload settles, and a double-send guard covers the
voice path's upload await. Voice recordings use references only when uploads
are enabled and keep the inline path otherwise, so the two flags stay
independent. Perception derives from the model's modalities (absent or
unknown means the workspace-only courtesy notice), the same memoized fact the
voice controls read. Sent and reloaded conversations render attachments
through the content route with authenticated blob fallback and no eager
downloads; durable records rebuild user file parts with filenames; delivery
events render as named per-file notices in live and replay. web/oss gains a
vitest setup with an explicit include list and junit reporting; the CI glob
addition for its report is left uncommitted because the push credential lacks
the workflow scope, recorded in the protocol. Dev stacks default the uploads
flag on; production flips separately as the rollout's fifth act.

Claude-Session: https://claude.ai/code/session_01A1XQVjHPYJgVBHWSNUphtx
…status

The status update rides the top lane deliberately: committing it on the docs
lane would rebase the whole train for a bookkeeping edit.

Claude-Session: https://claude.ai/code/session_01A1XQVjHPYJgVBHWSNUphtx
The rendered sentence under the answer was implementation-invented wording;
the product owner rejected it. D6's visible notice is the chip's crossed-eye
hint alone. The attachment_delivery events keep flowing and persisting; the
front end parses and ignores them, so a future surface can render them
without wire changes.

Claude-Session: https://claude.ai/code/session_01A1XQVjHPYJgVBHWSNUphtx
The previous commit's staging dropped this file's hunk; without it a replayed
delivery record still produced a rendered part.

Claude-Session: https://claude.ai/code/session_01A1XQVjHPYJgVBHWSNUphtx
The crossed-eye workspace-only hint goes the way of the in-message notice:
the first release ships no notice UI, and decision D6's visible notice waits
for a surface the product owner designs. The perception plumbing that existed
only to feed the hint goes with it; the voice controls keep their own modality
read. The per-turn count rises from the dark-shipped 5 to 100.

Claude-Session: https://claude.ai/code/session_01A1XQVjHPYJgVBHWSNUphtx
@mmabrouk
mmabrouk force-pushed the wp4-frontend-transport branch from 92797ad to c7ac4f6 Compare August 1, 2026 17:59
@mmabrouk
mmabrouk changed the base branch from wp3-sdk-producer to release/v0.107.0 August 1, 2026 18:14
@mmabrouk
mmabrouk merged commit 52507c2 into release/v0.107.0 Aug 1, 2026
40 of 41 checks passed
@mmabrouk
mmabrouk deleted the wp4-frontend-transport branch August 1, 2026 18:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature request New feature or request frontend size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant