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
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ _Italic text, formatted with single underscores_
<Radio
isChecked={variant === 'error'}
onChange={() => setVariant('error')}
name="bot-message-error"
name="bot-message-type"
label="Error"
id="error"
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { AlertActionLink, Form, FormGroup, Radio } from '@patternfly/react-core'

export const UserMessageExample: React.FunctionComponent = () => {
const [variant, setVariant] = React.useState('code');
const [isEditable, setIsEditable] = React.useState(true);

/* eslint-disable indent */
const renderContent = () => {
Expand Down Expand Up @@ -33,7 +34,7 @@ export const UserMessageExample: React.FunctionComponent = () => {
case 'image':
return image;
default:
return;
return '';
}
};
/* eslint-enable indent */
Expand Down Expand Up @@ -175,88 +176,131 @@ _Italic text, formatted with single underscores_
<FormGroup role="radiogroup" isInline fieldId="user-message-type" label="Message content type">
<Radio
isChecked={variant === 'code'}
onChange={() => setVariant('code')}
onChange={() => {
setVariant('code');
setIsEditable(true);
}}
name="user-message-type"
label="Code"
id="user-code"
/>
<Radio
isChecked={variant === 'inlineCode'}
onChange={() => setVariant('inlineCode')}
onChange={() => {
setVariant('inlineCode');
setIsEditable(true);
}}
name="user-message-type"
label="Inline code"
id="user-inline-code"
/>
<Radio
isChecked={variant === 'heading'}
onChange={() => setVariant('heading')}
onChange={() => {
setVariant('heading');
setIsEditable(true);
}}
name="user-message-type"
label="Heading"
id="user-heading"
/>
<Radio
isChecked={variant === 'blockQuotes'}
onChange={() => setVariant('blockQuotes')}
onChange={() => {
setVariant('blockQuotes');
setIsEditable(true);
}}
name="user-message-type"
label="Block quote"
id="user-block-quotes"
/>
<Radio
isChecked={variant === 'emphasis'}
onChange={() => setVariant('emphasis')}
onChange={() => {
setVariant('emphasis');
setIsEditable(true);
}}
name="user-message-type"
label="Emphasis"
id="user-emphasis"
/>
<Radio
isChecked={variant === 'link'}
onChange={() => setVariant('link')}
onChange={() => {
setVariant('link');
setIsEditable(true);
}}
name="user-message-type"
label="Link"
id="user-link"
/>
<Radio
isChecked={variant === 'unorderedList'}
onChange={() => setVariant('unorderedList')}
onChange={() => {
setVariant('unorderedList');
setIsEditable(true);
}}
name="user-message-type"
label="Unordered list"
id="user-unordered-list"
/>
<Radio
isChecked={variant === 'orderedList'}
onChange={() => setVariant('orderedList')}
onChange={() => {
setVariant('orderedList');
setIsEditable(true);
}}
name="user-message-type"
label="Ordered list"
id="user-ordered-list"
/>
<Radio
isChecked={variant === 'moreComplexList'}
onChange={() => setVariant('moreComplexList')}
onChange={() => {
setVariant('moreComplexList');
setIsEditable(true);
}}
name="user-message-type"
label="More complex list"
id="user-more-complex-list"
/>
<Radio
isChecked={variant === 'table'}
onChange={() => setVariant('table')}
onChange={() => {
setVariant('table');
setIsEditable(true);
}}
name="user-message-type"
label="Table"
id="user-table"
/>
<Radio
isChecked={variant === 'image'}
onChange={() => setVariant('image')}
onChange={() => {
setVariant('image');
setIsEditable(true);
}}
name="user-message-type"
label="Image"
id="user-image"
/>
<Radio
isChecked={variant === 'error'}
onChange={() => setVariant('error')}
name="user-message-error"
onChange={() => {
setVariant('error');
setIsEditable(true);
}}
name="user-message-type"
label="Error"
id="user-error"
/>
<Radio
isChecked={variant === 'editable'}
onChange={() => setVariant('editable')}
name="user-message-type"
label="Editable"
id="user-edit"
/>
</FormGroup>
</Form>
<Message
Expand All @@ -267,7 +311,10 @@ _Italic text, formatted with single underscores_
tableProps={
variant === 'table' ? { 'aria-label': 'App information and user roles for user messages' } : undefined
}
isEditable={variant === 'editable' ? isEditable : false}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do we want to toggle isEditable based on something inside the message when it's in the editable variant? It was a little odd to me using the example when I edited + saved and then couldn't get back to the edit interface without swapping to another variant and back.

I don't think this is a blocker since it's only example code quirks.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The trigger is something design is still working out! We'll make it a little more straightforward once they've made decisions.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

its in my to do list! here is the issue for it patternfly/patternfly-design-kit#801

error={variant === 'error' ? error : undefined}
onEditUpdate={() => setIsEditable(false)}
onEditCancel={() => setIsEditable(false)}
/>
</>
);
Expand Down
4 changes: 4 additions & 0 deletions packages/module/src/Message/Message.scss
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@
flex-wrap: wrap;
}

.pf-chatbot__message-edit-buttons {
--pf-v6-c-form__group--m-action--MarginBlockStart: 0;
}

@import './MessageLoading';
@import './CodeBlockMessage/CodeBlockMessage';
@import './TextMessage/TextMessage';
48 changes: 48 additions & 0 deletions packages/module/src/Message/Message.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -815,4 +815,52 @@ describe('Message', () => {
expect(screen.getByRole('heading', { name: /Could not load chat/i })).toBeTruthy();
expect(screen.queryByText('Test')).toBeFalsy();
});
it('should handle isEditable when there is message content', () => {
render(<Message avatar="./img" role="user" name="User" isEditable content="Test" />);
expect(screen.getByRole('textbox')).toBeTruthy();
expect(screen.getByRole('textbox')).toHaveValue('Test');
expect(screen.getByRole('button', { name: /Update/i })).toBeTruthy();
expect(screen.getByRole('button', { name: /Cancel/i })).toBeTruthy();
});
it('should handle isEditable when there is no message content', () => {
render(<Message avatar="./img" role="user" name="User" isEditable />);
expect(screen.getByRole('textbox')).toBeTruthy();
expect(screen.getByRole('textbox')).toHaveValue('');
expect(screen.getByRole('textbox')).toHaveAttribute('placeholder', 'Edit prompt message...');
expect(screen.getByRole('button', { name: /Update/i })).toBeTruthy();
expect(screen.getByRole('button', { name: /Cancel/i })).toBeTruthy();
});
it('should be able to change edit placeholder', () => {
render(<Message avatar="./img" role="user" name="User" isEditable editPlaceholder="I am a placeholder" />);
expect(screen.getByRole('textbox')).toBeTruthy();
expect(screen.getByRole('textbox')).toHaveValue('');
expect(screen.getByRole('textbox')).toHaveAttribute('placeholder', 'I am a placeholder');
});
it('should be able to change updateWord', () => {
render(<Message avatar="./img" role="user" name="User" isEditable updateWord="Submit" />);
expect(screen.getByRole('button', { name: /Submit/i })).toBeTruthy();
});
it('should be able to change cancelWord', () => {
render(<Message avatar="./img" role="user" name="User" isEditable cancelWord="Don't submit" />);
expect(screen.getByRole('button', { name: /Don't submit/i })).toBeTruthy();
});
it('should be able to add onEditUpdate', async () => {
const spy = jest.fn();
render(<Message avatar="./img" role="user" name="User" isEditable onEditUpdate={spy} />);
await userEvent.click(screen.getByRole('button', { name: /Update/i }));
expect(spy).toHaveBeenCalledTimes(1);
});
it('should be able to add onEditCancel', async () => {
const spy = jest.fn();
render(<Message avatar="./img" role="user" name="User" isEditable onEditCancel={spy} />);
await userEvent.click(screen.getByRole('button', { name: /Cancel/i }));
expect(spy).toHaveBeenCalledTimes(1);
});
it('should be able to add editFormProps', () => {
const { container } = render(
<Message avatar="./img" role="user" name="User" isEditable editFormProps={{ className: 'test' }} />
);
const form = container.querySelector('form');
expect(form).toHaveClass('test');
});
});
Loading
Loading