| b69ab31 | | | 1 | /** |
| b69ab31 | | | 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. |
| b69ab31 | | | 3 | * |
| b69ab31 | | | 4 | * This source code is licensed under the MIT license found in the |
| b69ab31 | | | 5 | * LICENSE file in the root directory of this source tree. |
| b69ab31 | | | 6 | */ |
| b69ab31 | | | 7 | |
| b69ab31 | | | 8 | import {useAtomValue} from 'jotai'; |
| b69ab31 | | | 9 | import clientToServerAPI from '../ClientToServerAPI'; |
| b69ab31 | | | 10 | import {T} from '../i18n'; |
| b69ab31 | | | 11 | import {writeAtom} from '../jotaiUtils'; |
| b69ab31 | | | 12 | |
| b69ab31 | | | 13 | import {ErrorNotice} from 'isl-components/ErrorNotice'; |
| b69ab31 | | | 14 | import {Icon} from 'isl-components/Icon'; |
| b69ab31 | | | 15 | import {minimalDisambiguousPaths} from 'shared/minimalDisambiguousPaths'; |
| b69ab31 | | | 16 | import {tracker} from '../analytics'; |
| b69ab31 | | | 17 | import {Collapsable} from '../Collapsable'; |
| b69ab31 | | | 18 | import {relativePath} from '../CwdSelector'; |
| b69ab31 | | | 19 | import {Link} from '../Link'; |
| b69ab31 | | | 20 | import platform from '../platform'; |
| b69ab31 | | | 21 | import {repoRelativeCwd} from '../repositoryData'; |
| b69ab31 | | | 22 | import {registerDisposable} from '../utils'; |
| b69ab31 | | | 23 | import './AICodeReviewStatus.css'; |
| b69ab31 | | | 24 | import { |
| b69ab31 | | | 25 | codeReviewStatusAtom, |
| b69ab31 | | | 26 | commentsByFilePathAtom, |
| b69ab31 | | | 27 | firstPassCommentData, |
| b69ab31 | | | 28 | firstPassCommentDataCount, |
| b69ab31 | | | 29 | firstPassCommentError, |
| b69ab31 | | | 30 | } from './firstPassCodeReviewAtoms'; |
| b69ab31 | | | 31 | |
| b69ab31 | | | 32 | registerDisposable( |
| b69ab31 | | | 33 | firstPassCommentData, |
| b69ab31 | | | 34 | clientToServerAPI.onMessageOfType('platform/gotAIReviewComments', data => { |
| b69ab31 | | | 35 | const result = data.comments; |
| b69ab31 | | | 36 | if (result.error) { |
| b69ab31 | | | 37 | writeAtom(codeReviewStatusAtom, 'error'); |
| b69ab31 | | | 38 | writeAtom(firstPassCommentError, result.error); |
| b69ab31 | | | 39 | tracker.error('AICodeReviewCompleted', 'AICodeReviewError', result.error); |
| b69ab31 | | | 40 | } else { |
| b69ab31 | | | 41 | writeAtom(codeReviewStatusAtom, 'success'); |
| b69ab31 | | | 42 | tracker.track('AICodeReviewCompleted', {extras: {commentCount: result.value.length}}); |
| b69ab31 | | | 43 | } |
| b69ab31 | | | 44 | }), |
| b69ab31 | | | 45 | import.meta.hot, |
| b69ab31 | | | 46 | ); |
| b69ab31 | | | 47 | |
| b69ab31 | | | 48 | export function AICodeReviewStatus(): JSX.Element | null { |
| b69ab31 | | | 49 | const repoRoot = useAtomValue(repoRelativeCwd); |
| b69ab31 | | | 50 | const status = useAtomValue(codeReviewStatusAtom); |
| b69ab31 | | | 51 | const commentCount = useAtomValue(firstPassCommentDataCount); |
| b69ab31 | | | 52 | const commentsByFilePath = useAtomValue(commentsByFilePathAtom); |
| b69ab31 | | | 53 | const error = useAtomValue(firstPassCommentError); |
| b69ab31 | | | 54 | const disambiguatedPaths = minimalDisambiguousPaths(Object.keys(commentsByFilePath)); |
| b69ab31 | | | 55 | |
| b69ab31 | | | 56 | // TODO: move this component to vscode/webview |
| b69ab31 | | | 57 | if (platform.platformName !== 'vscode' || status == null) { |
| b69ab31 | | | 58 | return null; |
| b69ab31 | | | 59 | } |
| b69ab31 | | | 60 | |
| b69ab31 | | | 61 | return ( |
| b69ab31 | | | 62 | <Collapsable |
| b69ab31 | | | 63 | className="comment-collapsable" |
| b69ab31 | | | 64 | title={ |
| b69ab31 | | | 65 | <div className="comment-collapsible-title"> |
| b69ab31 | | | 66 | <b> |
| b69ab31 | | | 67 | <T>Devmate Code Review</T> |
| b69ab31 | | | 68 | </b> |
| b69ab31 | | | 69 | <div className="comment-collapsible-title-status"> |
| b69ab31 | | | 70 | {status === 'success' && |
| b69ab31 | | | 71 | (commentCount > 0 ? ( |
| b69ab31 | | | 72 | <div className="comment-count"> |
| b69ab31 | | | 73 | {commentCount} |
| b69ab31 | | | 74 | <Icon icon="comment" /> |
| b69ab31 | | | 75 | </div> |
| b69ab31 | | | 76 | ) : ( |
| b69ab31 | | | 77 | <Icon icon="check" /> |
| b69ab31 | | | 78 | ))} |
| b69ab31 | | | 79 | {status === 'error' && <Icon icon="error" color="red" />} |
| b69ab31 | | | 80 | {status === 'running' && <Icon icon="loading" />} |
| b69ab31 | | | 81 | </div> |
| b69ab31 | | | 82 | </div> |
| b69ab31 | | | 83 | }> |
| b69ab31 | | | 84 | <div className="comment-content-container"> |
| b69ab31 | | | 85 | {status === 'running' && ( |
| b69ab31 | | | 86 | <div className="comment-loading">Devmate is reviewing your code...</div> |
| b69ab31 | | | 87 | )} |
| b69ab31 | | | 88 | {status === 'success' && |
| b69ab31 | | | 89 | (commentCount > 0 ? ( |
| b69ab31 | | | 90 | <div className="comment-list"> |
| b69ab31 | | | 91 | {Object.entries(commentsByFilePath).map(([filepath, comments], i) => |
| b69ab31 | | | 92 | comments.map((comment, j) => ( |
| b69ab31 | | | 93 | <div className="comment-container" key={comment.issueID || `${filepath}-${j}`}> |
| b69ab31 | | | 94 | <div className="comment-header"> |
| b69ab31 | | | 95 | <Link |
| b69ab31 | | | 96 | onClick={() => |
| b69ab31 | | | 97 | platform.openFile(relativePath(repoRoot, filepath), { |
| b69ab31 | | | 98 | line: comment.startLine, |
| b69ab31 | | | 99 | }) |
| b69ab31 | | | 100 | }> |
| b69ab31 | | | 101 | <b> |
| b69ab31 | | | 102 | {disambiguatedPaths[i]}:{comment.startLine} |
| b69ab31 | | | 103 | </b> |
| b69ab31 | | | 104 | </Link> |
| b69ab31 | | | 105 | </div> |
| b69ab31 | | | 106 | <div className="comment-body"> |
| b69ab31 | | | 107 | <T>{comment.description}</T> |
| b69ab31 | | | 108 | </div> |
| b69ab31 | | | 109 | </div> |
| b69ab31 | | | 110 | )), |
| b69ab31 | | | 111 | )} |
| b69ab31 | | | 112 | </div> |
| b69ab31 | | | 113 | ) : ( |
| b69ab31 | | | 114 | <div> |
| b69ab31 | | | 115 | <T>Everything looks good! Devmate didn't find any issues.</T> |
| b69ab31 | | | 116 | </div> |
| b69ab31 | | | 117 | ))} |
| b69ab31 | | | 118 | {status === 'error' && <ErrorNotice title="Failed to load comments" error={error} />} |
| b69ab31 | | | 119 | </div> |
| b69ab31 | | | 120 | </Collapsable> |
| b69ab31 | | | 121 | ); |
| b69ab31 | | | 122 | } |