mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-24 13:01:56 +00:00
fix(ui): constrain Lighthouse message overflow
This commit is contained in:
@@ -11,7 +11,23 @@ import {
|
||||
import { MessageBubble } from "./message-bubble";
|
||||
|
||||
vi.mock("streamdown", () => ({
|
||||
Streamdown: ({ children }: { children: ReactNode }) => <>{children}</>,
|
||||
Streamdown: ({ children }: { children: ReactNode }) => {
|
||||
const text = String(children);
|
||||
if (text.includes("very-wide-header")) {
|
||||
return (
|
||||
<table>
|
||||
<caption>Wide markdown table</caption>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{text}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
|
||||
return <>{children}</>;
|
||||
},
|
||||
defaultRehypePlugins: { katex: undefined, harden: undefined },
|
||||
}));
|
||||
|
||||
@@ -39,6 +55,38 @@ describe("MessageBubble", () => {
|
||||
expect(isBefore(firstText, toolCall)).toBe(true);
|
||||
expect(isBefore(toolCall, secondText)).toBe(true);
|
||||
});
|
||||
|
||||
it("should keep wide assistant tables inside the message width", () => {
|
||||
// Given
|
||||
const wideTableMessage = buildAssistantMessage([
|
||||
textPart(
|
||||
"part-1",
|
||||
"| very-wide-header | another-wide-header |\n| --- | --- |\n| very-long-cell-value-that-should-not-resize-the-message | value |",
|
||||
),
|
||||
]);
|
||||
|
||||
// When
|
||||
render(<MessageBubble message={wideTableMessage} />);
|
||||
|
||||
// Then
|
||||
const table = screen.getByRole("table", {
|
||||
name: "Wide markdown table",
|
||||
});
|
||||
const markdown = table.closest(".lighthouse-markdown");
|
||||
if (!(markdown instanceof HTMLElement)) {
|
||||
throw new Error("Expected markdown wrapper around assistant table");
|
||||
}
|
||||
|
||||
expect(markdown).toHaveClass("min-w-0", "max-w-full", "overflow-x-auto");
|
||||
expect(markdown.parentElement).toHaveClass("min-w-0");
|
||||
expect(markdown.parentElement?.parentElement).toHaveClass(
|
||||
"min-w-0",
|
||||
"max-w-full",
|
||||
);
|
||||
expect(markdown.parentElement?.parentElement?.parentElement).toHaveClass(
|
||||
"min-w-0",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
function isBefore(first: HTMLElement, second: HTMLElement): boolean {
|
||||
|
||||
@@ -43,20 +43,20 @@ export function MessageBubble({ message }: { message: LighthouseV2Message }) {
|
||||
return (
|
||||
<article
|
||||
className={cn(
|
||||
"group flex gap-3",
|
||||
"group flex min-w-0 gap-3",
|
||||
isUser ? "justify-end" : "justify-start",
|
||||
)}
|
||||
>
|
||||
{!isUser && <Bot className="text-text-neutral-tertiary mt-1 size-5" />}
|
||||
<div
|
||||
className={cn(
|
||||
"flex max-w-[min(760px,85%)] flex-col gap-1",
|
||||
"flex max-w-[min(760px,85%)] min-w-0 flex-col gap-1",
|
||||
isUser ? "items-end" : "items-start",
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
"rounded-[8px] px-4 py-3 text-sm",
|
||||
"max-w-full min-w-0 rounded-[8px] px-4 py-3 text-sm",
|
||||
isUser
|
||||
? "bg-button-primary text-black"
|
||||
: "bg-bg-neutral-tertiary text-text-neutral-primary",
|
||||
@@ -87,7 +87,7 @@ function AssistantParts({ parts }: { parts: LighthouseV2Part[] }) {
|
||||
const groups = groupAssistantParts(parts);
|
||||
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
<div className="min-w-0 space-y-3">
|
||||
{groups.map((group) =>
|
||||
group.type === ASSISTANT_PART_GROUP_TYPE.TOOL_CALL ? (
|
||||
<ToolCalls key={group.id} parts={group.parts} />
|
||||
|
||||
@@ -12,7 +12,7 @@ export function MessageMarkdown({
|
||||
isStreaming?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<div className="lighthouse-markdown">
|
||||
<div className="lighthouse-markdown max-w-full min-w-0 overflow-x-auto">
|
||||
<Streamdown
|
||||
parseIncompleteMarkdown
|
||||
shikiTheme={["github-light", "github-dark"]}
|
||||
|
||||
@@ -51,9 +51,9 @@ export function StreamingAssistantMessage({
|
||||
Boolean(streamState.activeTaskId) || streamState.toolCalls.length > 0;
|
||||
|
||||
return (
|
||||
<article className="flex justify-start gap-3">
|
||||
<article className="flex min-w-0 justify-start gap-3">
|
||||
<Bot className="text-text-neutral-tertiary mt-1 size-5" />
|
||||
<div className="bg-bg-neutral-tertiary text-text-neutral-primary max-w-[min(760px,85%)] rounded-[8px] px-4 py-3 text-sm">
|
||||
<div className="bg-bg-neutral-tertiary text-text-neutral-primary max-w-[min(760px,85%)] min-w-0 rounded-[8px] px-4 py-3 text-sm">
|
||||
{streamState.activityItems.length > 0 ? (
|
||||
<StreamingActivityGroups streamState={streamState} />
|
||||
) : (
|
||||
@@ -74,7 +74,7 @@ function StreamingActivityGroups({
|
||||
streamState.status === LIGHTHOUSE_V2_STREAM_STATUS.DISCONNECTED;
|
||||
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
<div className="min-w-0 space-y-3">
|
||||
{groups.map((group) =>
|
||||
group.type === STREAMING_ACTIVITY_GROUP_TYPE.TOOL_CALL ? (
|
||||
<StreamingToolCallGroup key={group.id} toolCalls={group.toolCalls} />
|
||||
|
||||
@@ -312,6 +312,11 @@
|
||||
.lighthouse-markdown p + ol {
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
.lighthouse-markdown table {
|
||||
min-width: 100%;
|
||||
width: max-content;
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== UTILITY LAYER ===== */
|
||||
|
||||
Reference in New Issue
Block a user