Skip to content

Commit

Permalink
Allow clicking links in chat profile description (Chainlit#1276), res…
Browse files Browse the repository at this point in the history
…olves Chainlit#1256

This pull request resolves Chainlit#1256, where users are unable to interact with chat profile descriptions, such as scrolling through long descriptions or clicking links within them. The modifications ensure that the description popover remains open and interactable when the mouse hovers over it, and closes appropriately when the mouse leaves the popover area or a selection is made.
  • Loading branch information
AidanShipperley authored Sep 7, 2024
1 parent 4664912 commit d4eeeb8
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 6 deletions.
2 changes: 1 addition & 1 deletion cypress/e2e/chat_profiles/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ async def chat_profile(current_user: cl.User):
),
cl.ChatProfile(
name="GPT-4",
markdown_description="The underlying LLM model is **GPT-4**, a *1.5T parameter model* trained on 3.5TB of text data.",
markdown_description="The underlying LLM model is **GPT-4**, a *1.5T parameter model* trained on 3.5TB of text data. [Learn more](https://example.com/gpt4)",
icon="https://picsum.photos/250",
starters=starters,
),
Expand Down
56 changes: 56 additions & 0 deletions cypress/e2e/chat_profiles/spec.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,60 @@ describe('Chat profiles', () => {

cy.get('#starter-ask-for-help').should('exist');
});

it('should keep chat profile description visible when hovering over a link', () => {
cy.visit('/');
cy.get("input[name='email']").type('admin');
cy.get("input[name='password']").type('admin');
cy.get("button[type='submit']").click();
cy.get('#chat-input').should('exist');

cy.get('#chat-profile-selector').parent().click();

// Force hover over GPT-4 profile to show description
cy.get('[data-test="select-item:GPT-4"]').trigger('mouseover', { force: true });

// Wait for the popover to appear and check its content
cy.get('#chat-profile-description').within(() => {
cy.contains('Learn more').should('be.visible');
});

// Check if the link is present in the description and has correct attributes
const linkSelector = '#chat-profile-description a:contains("Learn more")';
cy.get(linkSelector)
.should('have.attr', 'href', 'https://example.com/gpt4')
.and('have.attr', 'target', '_blank');

// Move mouse to the link
cy.get(linkSelector).trigger('mouseover', { force: true });

// Verify that the description is still visible after
cy.get('#chat-profile-description').within(() => {
cy.contains('Learn more').should('be.visible');
});

// Verify that the link is still present and clickable
cy.get(linkSelector)
.should('exist')
.and('be.visible')
.and('not.have.css', 'pointer-events', 'none')
.and('not.have.attr', 'disabled');

// Ensure the chat profile selector is still open
cy.get('[data-test="select-item:GPT-4"]').should('be.visible');

// Select GPT-4 profile
cy.get('[data-test="select-item:GPT-4"]').click();

// Verify the profile has been changed
submitMessage('hello');
cy.get('.step')
.should('have.length', 2)
.last()
.should(
'contain',
'starting chat with admin using the GPT-4 chat profile'
);

});
});
25 changes: 20 additions & 5 deletions frontend/src/components/molecules/chatProfiles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export default function ChatProfiles() {
const { clear } = useChatInteract();
const [newChatProfile, setNewChatProfile] = useState<string | null>(null);
const [openDialog, setOpenDialog] = useState(false);
const [popoverOpen, setPopoverOpen] = useState(false);
const navigate = useNavigate();

const handleClose = () => {
Expand Down Expand Up @@ -58,8 +59,6 @@ export default function ChatProfiles() {
const allowHtml = config?.features?.unsafe_allow_html;
const latex = config?.features?.latex;

const popoverOpen = Boolean(anchorEl);

const items = config.chatProfiles.map((item) => {
const icon = item.icon?.includes('/public')
? apiClient.buildEndpoint(item.icon)
Expand Down Expand Up @@ -94,7 +93,8 @@ export default function ChatProfiles() {
theme.palette.mode === 'light'
? '0px 2px 4px 0px #0000000D'
: '0px 10px 10px 0px #0000000D',
ml: 2
ml: 2,
pointerEvents: 'auto' // Allow mouse interaction with the chat profile description
}
}}
sx={{
Expand All @@ -110,6 +110,11 @@ export default function ChatProfiles() {
horizontal: 'left'
}}
disableRestoreFocus
onMouseEnter={() => setPopoverOpen(true)}
onMouseLeave={() => {
setPopoverOpen(false);
setAnchorEl(null);
}}
>
<Box
p={2}
Expand All @@ -134,18 +139,28 @@ export default function ChatProfiles() {
if (!item) return;
setChatProfileDescription(item.markdown_description);
setAnchorEl(event.currentTarget);
setPopoverOpen(true);
}}
onItemMouseLeave={() => setAnchorEl(null)}
onItemMouseLeave={() => setPopoverOpen(false)}
onChange={(e) => {
const newValue = e.target.value;

// Close the chat profile description when any selection is made
setPopoverOpen(false);
setAnchorEl(null);

// Handle user selection
setNewChatProfile(newValue);
if (firstInteraction) {
setOpenDialog(true);
} else {
handleConfirm(newValue);
}
}}
onClose={() => setAnchorEl(null)}
onClose={() => {
setPopoverOpen(false);
setAnchorEl(null);
}}
/>
<NewChatDialog
open={openDialog}
Expand Down

0 comments on commit d4eeeb8

Please sign in to comment.