Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions ui/desktop/src/components/MarkdownContent.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -322,4 +322,72 @@ more text`;
});
});
});

describe('URL Overflow Handling', () => {
it('handles very long URLs without overflow', async () => {
const longUrl =
'https://example-docs.com/document/d/1oruk3lcrnhoOXMFzBJB8X6qQ5AtQTmj4XXxXk3xK-3g/edit?usp=sharing&mode=edit&version=1';
const content = `Check out this document: ${longUrl}

Another very long URL: https://www.example.com/very/long/path/with/many/segments/and/parameters?param1=value1&param2=value2&param3=value3&param4=value4&param5=value5`;

const { container } = render(<MarkdownContent content={content} />);

await waitFor(() => {
expect(screen.getByText(/Check out this document/)).toBeInTheDocument();
expect(screen.getByText(/Another very long URL/)).toBeInTheDocument();
});

// Check that URLs are rendered as links
const links = container.querySelectorAll('a');
expect(links.length).toBeGreaterThan(0);

// Check that links have proper CSS classes for word breaking
links.forEach((link) => {
// The CSS should allow the text to break
expect(link).toBeInTheDocument();
});
});

it('handles markdown links with long URLs', async () => {
const longUrl =
'https://example-docs.com/document/d/1oruk3lcrnhoOXMFzBJB8X6qQ5AtQTmj4XXxXk3xK-3g/edit?usp=sharing&mode=edit&version=1';
const content = `[Click here for the document](${longUrl})`;

render(<MarkdownContent content={content} />);

await waitFor(() => {
const link = screen.getByRole('link', { name: 'Click here for the document' });
expect(link).toBeInTheDocument();
expect(link).toHaveAttribute('href', longUrl);
});
});

it('handles multiple long URLs in the same message', async () => {
const content = `Here are some long URLs:

1. Example Doc: https://example-docs.com/document/d/1oruk3lcrnhoOXMFzBJB8X6qQ5AtQTmj4XXxXk3xK-3g/edit?usp=sharing&mode=edit&version=1
2. Another long URL: https://www.example.com/very/long/path/with/many/segments/and/parameters?param1=value1&param2=value2&param3=value3
3. Third URL: https://api.example.com/v1/users/12345/documents/67890/attachments/abcdef123456789?format=json&include=metadata&sort=created_at`;

render(<MarkdownContent content={content} />);

await waitFor(() => {
expect(screen.getByText(/Here are some long URLs/)).toBeInTheDocument();
expect(screen.getByText(/Example Doc/)).toBeInTheDocument();
expect(screen.getByText(/Another long URL/)).toBeInTheDocument();
expect(screen.getByText(/Third URL/)).toBeInTheDocument();
});
});

it('applies word-break CSS classes to the container', () => {
const content = 'Test content';
render(<MarkdownContent content={content} />);

const markdownContainer = document.querySelector('.prose');
expect(markdownContainer).toBeInTheDocument();
expect(markdownContainer).toHaveClass('prose-a:break-all');
expect(markdownContainer).toHaveClass('prose-a:overflow-wrap-anywhere');
});
});
});
19 changes: 10 additions & 9 deletions ui/desktop/src/components/MarkdownContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,21 +139,22 @@ const MarkdownContent = memo(function MarkdownContent({

return (
<div
className={`w-full overflow-x-hidden prose prose-sm text-text-default dark:prose-invert max-w-full word-breakfont-sans
className={`w-full overflow-x-hidden prose prose-sm text-text-default dark:prose-invert max-w-full word-break font-sans
prose-pre:p-0 prose-pre:m-0 !p-0
prose-code:break-all prose-code:whitespace-pre-wrapprose-code:font-sans
prose-code:break-all prose-code:whitespace-pre-wrap prose-code:font-sans
prose-a:break-all prose-a:overflow-wrap-anywhere
prose-table:table prose-table:w-full
prose-blockquote:text-inherit
prose-td:border prose-td:border-border-default prose-td:p-2
prose-th:border prose-th:border-border-default prose-th:p-2
prose-thead:bg-background-default
prose-h1:text-2xl prose-h1:font-normal prose-h1:mb-5 prose-h1:mt-0prose-h1:font-sans
prose-h2:text-xl prose-h2:font-normal prose-h2:mb-4 prose-h2:mt-4prose-h2:font-sans
prose-h3:text-lg prose-h3:font-normal prose-h3:mb-3 prose-h3:mt-3prose-h3:font-sans
prose-p:mt-0 prose-p:mb-2prose-p:font-sans
prose-ol:my-2prose-ol:font-sans
prose-ul:mt-0 prose-ul:mb-3prose-ul:font-sans
prose-li:m-0prose-li:font-sans ${className}`}
prose-h1:text-2xl prose-h1:font-normal prose-h1:mb-5 prose-h1:mt-0 prose-h1:font-sans
prose-h2:text-xl prose-h2:font-normal prose-h2:mb-4 prose-h2:mt-4 prose-h2:font-sans
prose-h3:text-lg prose-h3:font-normal prose-h3:mb-3 prose-h3:mt-3 prose-h3:font-sans
prose-p:mt-0 prose-p:mb-2 prose-p:font-sans
prose-ol:my-2 prose-ol:font-sans
prose-ul:mt-0 prose-ul:mb-3 prose-ul:font-sans
prose-li:m-0 prose-li:font-sans ${className}`}
>
<ReactMarkdown
remarkPlugins={[remarkGfm, remarkBreaks]}
Expand Down
Loading