From 8b9a5b0a12bb43def0cc545cb67bbb8a4ebb6393 Mon Sep 17 00:00:00 2001 From: Mahmoud Mabrouk Date: Fri, 5 Jun 2026 11:21:26 +0200 Subject: [PATCH 1/2] fix(frontend): forward className in Editor noProvider mode and clean up workarounds The shared Editor dropped `className`/`editorClassName` when rendered with `noProvider` (it only applied the class on the EditorProvider path). Forward it to EditorInner and apply it to the editor container in that mode too. With the prop working, clean up the call sites that relied on the drop: - ChatMessageEditor: move the message text/placeholder alignment from the globals.css workaround to editorClassName; globals.css now only carries the antd role-button override that cannot go through the prop. - VariableControlAdapter: stop forwarding the generation-row container class as editorClassName (it is a container/cell-strip style that would strip the editor's border and gutter); it stays on the container only. - GenerationComparisonChatOutput: pad the editor body via editorClassName instead of the [&_.agenta-editor-wrapper] container hack. --- web/oss/src/styles/globals.css | 28 +++++-------------- .../GenerationComparisonChatOutput/index.tsx | 7 +++-- .../adapters/VariableControlAdapter.tsx | 9 +++++- .../components/ChatMessageEditor.tsx | 17 +++++++---- web/packages/agenta-ui/src/Editor/Editor.tsx | 14 +++++++++- 5 files changed, 45 insertions(+), 30 deletions(-) diff --git a/web/oss/src/styles/globals.css b/web/oss/src/styles/globals.css index bcf2162872..35ebc409b2 100644 --- a/web/oss/src/styles/globals.css +++ b/web/oss/src/styles/globals.css @@ -206,28 +206,14 @@ body { } } -/* Align the message text with the first character of the role label above it, - with the same symmetric horizontal inset on the role, the text, and the - placeholder. The single inset value lives in --ag-message-inline-pad. - - Notes: - - The role label is an antd Button whose default padding is wider than the - inset (Tailwind's px-2 on it loses to antd), so it is pinned with !important. - - The text is padded here in CSS rather than via an editor prop because - ChatMessageEditor renders the Editor with `noProvider`, a mode where - `className`/`editorClassName` is currently dropped (known bug, tracked - separately). JSON/code editors are excluded; they have a line-number gutter. */ -.agenta-chat-message-editor { - --ag-message-inline-pad: 8px; -} +/* Align the role label's first character with the message text below it. + The message text and placeholder are inset 8px via ChatMessageEditor's + editorClassName prop; this rule pins the role label to the same 8px. The role + label is an antd Button whose default padding is wider than 8px and ignores + Tailwind's px-2, so the override needs !important. Scoped to the message + editor via the .agenta-chat-message-editor marker class. */ .agenta-chat-message-editor .message-user-select { - padding-inline: var(--ag-message-inline-pad) !important; -} -.agenta-chat-message-editor .editor-input:not(.code-only) { - padding-inline: var(--ag-message-inline-pad); -} -.agenta-chat-message-editor .editor-placeholder { - left: var(--ag-message-inline-pad); + padding-inline: 8px !important; } /** Align the input search with the search box **/ diff --git a/web/packages/agenta-playground-ui/src/components/ExecutionItemComparisonView/GenerationComparisonChatOutput/index.tsx b/web/packages/agenta-playground-ui/src/components/ExecutionItemComparisonView/GenerationComparisonChatOutput/index.tsx index 8bff03803b..24e99dcabd 100644 --- a/web/packages/agenta-playground-ui/src/components/ExecutionItemComparisonView/GenerationComparisonChatOutput/index.tsx +++ b/web/packages/agenta-playground-ui/src/components/ExecutionItemComparisonView/GenerationComparisonChatOutput/index.tsx @@ -150,8 +150,11 @@ const GenerationComparisonChatOutputCell = ({ allowFileUpload: true, }} messageProps={{ - className: - "!p-0 [&_.agenta-editor-wrapper]:!p-3 !mt-0 [&:nth-child(1)]:!mt-0 mt-2", + className: "!p-0 !mt-0 [&:nth-child(1)]:!mt-0 mt-2", + // Editor body padding now goes through the + // editorClassName prop (works after the noProvider + // className fix), replacing the previous + // `[&_.agenta-editor-wrapper]:!p-3` container hack. editorClassName: "!p-3", headerClassName: "min-h-[48px] px-2 border-0 border-b border-solid border-[var(--ag-rgba-051729-06)]", diff --git a/web/packages/agenta-playground-ui/src/components/adapters/VariableControlAdapter.tsx b/web/packages/agenta-playground-ui/src/components/adapters/VariableControlAdapter.tsx index 0a9ce04c2c..0018464a4d 100644 --- a/web/packages/agenta-playground-ui/src/components/adapters/VariableControlAdapter.tsx +++ b/web/packages/agenta-playground-ui/src/components/adapters/VariableControlAdapter.tsx @@ -549,7 +549,14 @@ const VariableControlAdapter: React.FC = ({ handleChange={handleChange} initialValue={effectiveValue} value={effectiveValue} - editorClassName={className} + // NOTE: the parent's `className` is a container/cell-strip style + // (e.g. `*:!border-none px-3`) and is applied to the container + // below. It must NOT be forwarded to the editor body, where it + // would strip the editor's own border and gutter (see the + // matching note on the code-editor branch above). It was + // previously passed as `editorClassName` but silently dropped by + // the `noProvider` className bug; now that the bug is fixed, the + // forward is removed so it stays a container-only style. placeholder={effectivePlaceholder} disabled={isEffectivelyDisabled} className={clsx( diff --git a/web/packages/agenta-ui/src/ChatMessage/components/ChatMessageEditor.tsx b/web/packages/agenta-ui/src/ChatMessage/components/ChatMessageEditor.tsx index 85ceca76ef..9add5fe5a3 100644 --- a/web/packages/agenta-ui/src/ChatMessage/components/ChatMessageEditor.tsx +++ b/web/packages/agenta-ui/src/ChatMessage/components/ChatMessageEditor.tsx @@ -210,14 +210,21 @@ const ChatMessageEditorInner: React.FC = ({ // // Kaosiso QA 2026-06-02 (also reproduces in production). disableDebounce - editorClassName={editorClassName} + // Inset the message text and its placeholder by 8px so they line up + // with the role label above. Goes through editorClassName (the proper + // prop) now that the noProvider className bug is fixed. Code editors + // (JSON/tool) keep their own gutter, so they are excluded via + // `:not(.code-only)`. The role label is an antd button outside the + // editor and is aligned via the scoped rule in globals.css. + editorClassName={cn( + "[&_.editor-input:not(.code-only)]:px-2 [&_.editor-placeholder]:left-2", + editorClassName, + )} placeholder={placeholder} disabled={disabled} state={disabled ? "readOnly" : state} - // `agenta-chat-message-editor` is the styling hook used in globals.css - // to align the message text with the role label (see that file). The - // padding can't go through `editorClassName` because ChatMessageEditor - // renders the Editor with `noProvider`, where `className` is dropped. + // `agenta-chat-message-editor` scopes the role-label alignment rule in + // globals.css (the role is an antd button, not part of the editor). className={cn( "agenta-chat-message-editor relative", flexLayouts.column, diff --git a/web/packages/agenta-ui/src/Editor/Editor.tsx b/web/packages/agenta-ui/src/Editor/Editor.tsx index 2b3378c302..a4cae15880 100644 --- a/web/packages/agenta-ui/src/Editor/Editor.tsx +++ b/web/packages/agenta-ui/src/Editor/Editor.tsx @@ -173,6 +173,7 @@ const EditorInner = forwardRef( disableIndentationPlugin = false, useNativeCodeNodes = false, diffExtensionConfig, + className, ...rest }: EditorProps, ref, @@ -755,7 +756,17 @@ const EditorInner = forwardRef( }, [codeOnly, editor, effectiveValue, hydrateRichTextFromControlledValue]) return ( -
+
Date: Fri, 5 Jun 2026 11:58:04 +0200 Subject: [PATCH 2/2] fix(frontend): stop role-alignment inset stacking with comparison cell padding The comparison view renders messages with their own editor padding (!p-3 cells). The role-alignment inset added by ChatMessageEditor stacked on top of that, over-padding the message text, and the assistant output cell also double-padded (the [&_.agenta-editor-wrapper]:!p-3 hack plus editorClassName). Add an alignTextWithRole prop (default true) to ChatMessageEditor; the comparison view passes false so the inset and role pin are skipped there. Remove the leftover wrapper-padding hack so the comparison cells pad the editor once, via editorClassName. --- .../GenerationComparisonChatOutput/index.tsx | 18 +++++++++++----- .../components/ChatMessageEditor.tsx | 21 ++++++++++++++----- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/web/packages/agenta-playground-ui/src/components/ExecutionItemComparisonView/GenerationComparisonChatOutput/index.tsx b/web/packages/agenta-playground-ui/src/components/ExecutionItemComparisonView/GenerationComparisonChatOutput/index.tsx index 24e99dcabd..d673ed3f65 100644 --- a/web/packages/agenta-playground-ui/src/components/ExecutionItemComparisonView/GenerationComparisonChatOutput/index.tsx +++ b/web/packages/agenta-playground-ui/src/components/ExecutionItemComparisonView/GenerationComparisonChatOutput/index.tsx @@ -151,11 +151,14 @@ const GenerationComparisonChatOutputCell = ({ }} messageProps={{ className: "!p-0 !mt-0 [&:nth-child(1)]:!mt-0 mt-2", - // Editor body padding now goes through the - // editorClassName prop (works after the noProvider - // className fix), replacing the previous + // Comparison cells set their own editor padding via + // editorClassName (works after the noProvider className + // fix), replacing the previous // `[&_.agenta-editor-wrapper]:!p-3` container hack. + // alignTextWithRole is off so the role-alignment inset + // does not stack on top of this padding. editorClassName: "!p-3", + alignTextWithRole: false, headerClassName: "min-h-[48px] px-2 border-0 border-b border-solid border-[var(--ag-rgba-051729-06)]", footerClassName: "px-2", @@ -201,9 +204,14 @@ const GenerationComparisonChatOutputCell = ({ withControls={false} hideUserMessage messageProps={{ - className: - "!p-0 [&_.agenta-editor-wrapper]:!p-3 !mt-0 [&:nth-child(1)]:!mt-0 mt-2", + // Padding via editorClassName only (the + // [&_.agenta-editor-wrapper]:!p-3 hack is removed so it does + // not double up now that editorClassName works), and + // alignTextWithRole off so the role-alignment inset does not + // stack on top. + className: "!p-0 !mt-0 [&:nth-child(1)]:!mt-0 mt-2", editorClassName: "!p-3", + alignTextWithRole: false, headerClassName: "min-h-[48px] border-0 border-b border-solid border-[var(--ag-rgba-051729-06)]", footerClassName: "px-2 !m-0", diff --git a/web/packages/agenta-ui/src/ChatMessage/components/ChatMessageEditor.tsx b/web/packages/agenta-ui/src/ChatMessage/components/ChatMessageEditor.tsx index 9add5fe5a3..a0abbd5aae 100644 --- a/web/packages/agenta-ui/src/ChatMessage/components/ChatMessageEditor.tsx +++ b/web/packages/agenta-ui/src/ChatMessage/components/ChatMessageEditor.tsx @@ -74,6 +74,14 @@ export interface ChatMessageEditorProps { * up via an internal synchronizer mounted inside the EditorProvider. */ markdownView?: boolean + /** + * Inset the message text + placeholder so they line up with the role label + * above (the default tight message layout). Set to false for surfaces that + * apply their own editor padding (e.g. the comparison view's `!p-3` cells), + * where the alignment inset would stack on top and over-pad the text. + * @default true + */ + alignTextWithRole?: boolean } /** @@ -134,6 +142,7 @@ const ChatMessageEditorInner: React.FC = ({ onFocusChange, maxPasteChars = DEFAULT_MAX_TEXT_PASTE_CHARS, onPasteLimitExceeded, + alignTextWithRole = true, ...props }) => { const selectOptions = useMemo( @@ -215,18 +224,20 @@ const ChatMessageEditorInner: React.FC = ({ // prop) now that the noProvider className bug is fixed. Code editors // (JSON/tool) keep their own gutter, so they are excluded via // `:not(.code-only)`. The role label is an antd button outside the - // editor and is aligned via the scoped rule in globals.css. + // editor and is aligned via the `.agenta-chat-message-editor` rule in + // globals.css. Both are skipped when alignTextWithRole is false (e.g. + // the comparison view, which applies its own editor padding). editorClassName={cn( - "[&_.editor-input:not(.code-only)]:px-2 [&_.editor-placeholder]:left-2", + alignTextWithRole && + "[&_.editor-input:not(.code-only)]:px-2 [&_.editor-placeholder]:left-2", editorClassName, )} placeholder={placeholder} disabled={disabled} state={disabled ? "readOnly" : state} - // `agenta-chat-message-editor` scopes the role-label alignment rule in - // globals.css (the role is an antd button, not part of the editor). className={cn( - "agenta-chat-message-editor relative", + alignTextWithRole && "agenta-chat-message-editor", + "relative", flexLayouts.column, gapClasses.xs, "rounded-md",