3.7 KB133 lines
Blame
1/**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8import type {DiffComment, SuggestedChange} from 'isl/src/types';
9
10import * as stylex from '@stylexjs/stylex';
11import {Badge} from 'isl-components/Badge';
12import {Column, Row} from 'isl-components/Flex';
13import {Icon} from 'isl-components/Icon';
14import {AvatarImg} from 'isl/src/Avatar';
15import {ArchivedReasonType, ArchivedStateType, CodePatchSuggestionStatus} from 'isl/src/types';
16
17const styles = stylex.create({
18 avatarColumn: {
19 flexShrink: 0,
20 },
21 avatar: {
22 marginBlock: '5px',
23 },
24 commentColumn: {
25 gap: 1,
26 },
27 commentAuthorRow: {
28 gap: 6,
29 },
30 commentAuthor: {
31 lineHeight: '17px',
32 textWrap: 'nowrap',
33 opacity: 0.75,
34 },
35 versionAbbr: {
36 opacity: 0.5,
37 whiteSpace: 'nowrap',
38 },
39 primaryBadge: {
40 backgroundColor: 'var(--button-primary-background)',
41 color: 'var(--button-primary-foreground)',
42 },
43 suggestionBadge: {
44 gap: '2px',
45 },
46});
47
48function getSuggestionBadgeLabel(
49 suggestedChange: SuggestedChange | undefined,
50): {text: string; isPrimary: boolean} | undefined {
51 if (suggestedChange?.patch == null) {
52 return undefined;
53 }
54 if (suggestedChange.status === CodePatchSuggestionStatus.Declined) {
55 return {text: 'Rejected', isPrimary: false};
56 }
57 if (suggestedChange.archivedState === ArchivedStateType.ARCHIVED) {
58 switch (suggestedChange.archivedReason) {
59 case ArchivedReasonType.APPLIED_IN_EDITOR:
60 return {text: 'Applied Inline', isPrimary: true};
61 case ArchivedReasonType.APPLIED_MERGED:
62 case ArchivedReasonType.APPLIED_STACKED_DIFF:
63 return {text: 'Merged', isPrimary: false};
64 case ArchivedReasonType.AUTHOR_DISCARDED:
65 return {text: 'Rejected', isPrimary: false};
66 case ArchivedReasonType.STALE_DIFF_CLOSED:
67 case ArchivedReasonType.STALE_FILE_CHANGED:
68 return {text: 'Closed', isPrimary: false};
69 }
70 }
71 if (suggestedChange.status === CodePatchSuggestionStatus.Accepted) {
72 return {text: 'Accepted', isPrimary: true};
73 }
74 return {text: 'Suggestion', isPrimary: true};
75}
76
77export function CommentCardBadge({
78 label,
79 icon,
80}: {
81 label: {text: string; isPrimary: boolean};
82 icon: string;
83}) {
84 return (
85 <Badge xstyle={label.isPrimary && styles.primaryBadge}>
86 <Row xstyle={styles.suggestionBadge}>
87 <span>
88 <Icon icon={icon} size="XS" />
89 </span>
90 {label.text}
91 </Row>
92 </Badge>
93 );
94}
95
96export default function InlineCommentContent({
97 comment,
98 isHeadComment = false,
99 isHidden = false,
100 isLatestVersion = true,
101 versionAbbr,
102}: {
103 comment: DiffComment;
104 isHeadComment?: boolean;
105 isHidden?: boolean;
106 isLatestVersion?: boolean;
107 versionAbbr?: string;
108}) {
109 const label = getSuggestionBadgeLabel(comment.suggestedChange);
110 return (
111 <Column alignStart xstyle={styles.commentColumn}>
112 <Row xstyle={styles.commentAuthorRow}>
113 <Column alignStart xstyle={styles.avatarColumn}>
114 <AvatarImg
115 username={comment.author}
116 url={comment.authorAvatarUri}
117 xstyle={styles.avatar}
118 />
119 </Column>
120 <div {...stylex.props(styles.commentAuthor)}>{comment.authorName}</div>
121 {label && <CommentCardBadge label={label} icon="code" />}
122 {isHidden && (
123 <CommentCardBadge label={{text: 'Hidden', isPrimary: false}} icon="eye-closed" />
124 )}
125 {isHeadComment && !isLatestVersion && versionAbbr && (
126 <div {...stylex.props(styles.versionAbbr)}>[Original comment on {versionAbbr}]</div>
127 )}
128 </Row>
129 <Row>{comment.content}</Row>
130 </Column>
131 );
132}
133