Skip to content

Commit

Permalink
feat(autofix): Add Q&A interaction (#78227)
Browse files Browse the repository at this point in the history
Frontend changes that allow users to see questions asked by Autofix and
respond.

Also contains other minor UI tweaks.

<img width="624" alt="Screenshot 2024-09-25 at 10 23 05 AM"
src="https://github.com/user-attachments/assets/68ab9c3d-0f41-41a8-ab66-3a693702bab0">
  • Loading branch information
roaga committed Sep 27, 2024
1 parent 44fa12b commit 2248f35
Show file tree
Hide file tree
Showing 10 changed files with 429 additions and 113 deletions.
4 changes: 2 additions & 2 deletions static/app/components/events/autofix/autofixDrawer.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ describe('AutofixDrawer', () => {

expect(screen.getByRole('heading', {name: 'Autofix'})).toBeInTheDocument();

expect(screen.getByText('Autofix is ready to start')).toBeInTheDocument();
expect(screen.getByText('Ready to start')).toBeInTheDocument();

const startButton = screen.getByRole('button', {name: 'Start'});
expect(startButton).toBeInTheDocument();
Expand Down Expand Up @@ -88,7 +88,7 @@ describe('AutofixDrawer', () => {
await userEvent.click(startOverButton);

await waitFor(() => {
expect(screen.getByText('Autofix is ready to start')).toBeInTheDocument();
expect(screen.getByText('Ready to start')).toBeInTheDocument();
expect(screen.getByRole('button', {name: 'Start'})).toBeInTheDocument();
});
});
Expand Down
39 changes: 22 additions & 17 deletions static/app/components/events/autofix/autofixDrawer.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {useState} from 'react';
import styled from '@emotion/styled';

import bannerImage from 'sentry-images/spot/ai-suggestion-banner.svg';
import bannerImage from 'sentry-images/insights/module-upsells/insights-module-upsell.svg';

import ProjectAvatar from 'sentry/components/avatar/projectAvatar';
import {Breadcrumbs as NavigationBreadcrumbs} from 'sentry/components/breadcrumbs';
Expand Down Expand Up @@ -34,26 +34,27 @@ function AutofixStartBox({onSend}: AutofixStartBoxProps) {

return (
<StartBox>
<Header>Autofix is ready to start</Header>
<IllustrationContainer>
<Illustration src={bannerImage} />
</IllustrationContainer>
<Header>Ready to start</Header>
<br />
<p>
We'll begin by trying to figure out the root cause, analyzing the issue details
and the codebase. If you have any other helpful context on the issue before we
begin, you can share that below.
</p>
<Input
type="text"
value={message}
onChange={e => setMessage(e.target.value)}
placeholder={'Provide any extra context here...'}
/>
<br />
<Button priority="primary" onClick={send}>
Start
</Button>
<IllustrationContainer>
<Illustration src={bannerImage} />
</IllustrationContainer>
<Row>
<Input
type="text"
value={message}
onChange={e => setMessage(e.target.value)}
placeholder={'Provide any extra context here...'}
/>
<Button priority="primary" onClick={send}>
Start
</Button>
</Row>
</StartBox>
);
}
Expand Down Expand Up @@ -125,8 +126,13 @@ export function AutofixDrawer({group, project, event}: AutofixDrawerProps) {
);
}

const Row = styled('div')`
display: flex;
gap: ${space(1)};
`;

const IllustrationContainer = styled('div')`
padding-top: ${space(4)};
padding: ${space(4)} 0 ${space(4)} 0;
`;

const Illustration = styled('img')`
Expand All @@ -137,7 +143,6 @@ const StartBox = styled('div')`
padding: ${space(2)};
display: flex;
flex-direction: column;
justify-content: center;
height: 100%;
width: 100%;
`;
Expand Down
102 changes: 97 additions & 5 deletions static/app/components/events/autofix/autofixInsightCards.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,52 @@
import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';

import AutofixInsightCards from 'sentry/components/events/autofix/autofixInsightCards';
import type {AutofixInsight} from 'sentry/components/events/autofix/types';

jest.mock('sentry/utils/marked', () => ({
singleLineRenderer: jest.fn(text => text),
}));

const sampleInsights = [
const sampleInsights: AutofixInsight[] = [
{
breadcrumb_context: [],
codebase_context: [],
breadcrumb_context: [
{
body: 'Breadcrumb body',
category: 'ui',
level: 'info',
data_as_json: '{"testData": "testValue"}',
type: 'info',
},
],
codebase_context: [
{
snippet: 'console.log("Hello, World!");',
repo_name: 'sample-repo',
file_path: 'src/index.js',
},
],
error_message_context: ['Error message 1'],
insight: 'Sample insight 1',
justification: 'Sample justification 1',
stacktrace_context: [
{
code_snippet: 'function() { throw new Error("Test error"); }',
repo_name: 'sample-repo',
file_name: 'src/error.js',
vars_as_json: '{"testVar": "testValue"}',
col_no: 1,
line_no: 1,
function: 'testFunction',
},
],
},
{
insight: 'User message',
justification: 'USER',
breadcrumb_context: [],
stacktrace_context: [],
codebase_context: [],
error_message_context: [],
},
];

Expand Down Expand Up @@ -43,13 +76,72 @@ describe('AutofixInsightCards', () => {
it('renders insights correctly', () => {
renderComponent();
expect(screen.getByText('Sample insight 1')).toBeInTheDocument();
expect(screen.getByText('User message')).toBeInTheDocument();
});

it('renders breadcrumb context correctly', async () => {
renderComponent();
const contextButton = screen.getByText('Context');
await userEvent.click(contextButton);
expect(screen.getByText('Breadcrumb body')).toBeInTheDocument();
expect(screen.getByText('info')).toBeInTheDocument();
});

it('renders codebase context correctly', async () => {
renderComponent();
const contextButton = screen.getByText('Context');
await userEvent.click(contextButton);
expect(screen.getByText('console.log("Hello, World!");')).toBeInTheDocument();
expect(screen.getByText('src/index.js')).toBeInTheDocument();
});

it('expands context when clicked', async () => {
it('renders stacktrace context correctly', async () => {
renderComponent();
const contextButton = screen.getByText('Context');
await userEvent.click(contextButton);
expect(
screen.getByText('function() { throw new Error("Test error"); }')
).toBeInTheDocument();
expect(screen.getByText('src/error.js')).toBeInTheDocument();
expect(screen.getByText('testVar')).toBeInTheDocument();
});

it('renders user messages differently', () => {
renderComponent();
const userMessage = screen.getByText('User message');
expect(userMessage.closest('div')).toHaveStyle('color: inherit');
});

it('renders "No insights yet" message when there are no insights', () => {
renderComponent({insights: []});
expect(
screen.getByText(/Autofix will share important conclusions here/)
).toBeInTheDocument();
});

it('toggles context expansion correctly', async () => {
renderComponent();
const contextButton = screen.getByText('Context');

await userEvent.click(contextButton);
expect(screen.getByText('Sample justification 1')).toBeInTheDocument();
expect(screen.getByText('`Error message 1`')).toBeInTheDocument();

await userEvent.click(contextButton);
expect(screen.queryByText('Sample justification 1')).not.toBeInTheDocument();
});

it('renders multiple insights correctly', () => {
const multipleInsights = [
...sampleInsights,
{
insight: 'Another insight',
justification: 'Another justification',
error_message_context: ['Another error message'],
},
];
renderComponent({insights: multipleInsights});
expect(screen.getByText('Sample insight 1')).toBeInTheDocument();
expect(screen.getByText('User message')).toBeInTheDocument();
expect(screen.getByText('Another insight')).toBeInTheDocument();
});
});
Loading

0 comments on commit 2248f35

Please sign in to comment.