| 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 type {ExclusiveOr} from 'shared/typeUtils'; |
| b69ab31 | | | 9 | import type {OneIndexedLineNumber} from './types'; |
| b69ab31 | | | 10 | |
| b69ab31 | | | 11 | type Props = { |
| b69ab31 | | | 12 | beforeLineNumber: number | null; |
| b69ab31 | | | 13 | before: React.ReactFragment | null; |
| b69ab31 | | | 14 | afterLineNumber: number | null; |
| b69ab31 | | | 15 | after: React.ReactFragment | null; |
| b69ab31 | | | 16 | rowType: SplitDiffRowType; |
| b69ab31 | | | 17 | path: string; |
| b69ab31 | | | 18 | unified: boolean; |
| b69ab31 | | | 19 | openFileToLine?: (lineNumber: OneIndexedLineNumber) => unknown; |
| b69ab31 | | | 20 | }; |
| b69ab31 | | | 21 | |
| b69ab31 | | | 22 | type SplitDiffRowType = 'add' | 'common' | 'modify' | 'remove' | 'expanded'; |
| b69ab31 | | | 23 | |
| b69ab31 | | | 24 | export default function SplitDiffRow({ |
| b69ab31 | | | 25 | beforeLineNumber, |
| b69ab31 | | | 26 | before, |
| b69ab31 | | | 27 | afterLineNumber, |
| b69ab31 | | | 28 | after, |
| b69ab31 | | | 29 | rowType, |
| b69ab31 | | | 30 | path, |
| b69ab31 | | | 31 | unified, |
| b69ab31 | | | 32 | openFileToLine, |
| b69ab31 | | | 33 | }: Props): [JSX.Element, JSX.Element, JSX.Element, JSX.Element] { |
| b69ab31 | | | 34 | let beforeClass; |
| b69ab31 | | | 35 | let afterClass; |
| b69ab31 | | | 36 | switch (rowType) { |
| b69ab31 | | | 37 | case 'remove': |
| b69ab31 | | | 38 | beforeClass = 'patch-remove-line'; |
| b69ab31 | | | 39 | afterClass = undefined; |
| b69ab31 | | | 40 | break; |
| b69ab31 | | | 41 | case 'modify': |
| b69ab31 | | | 42 | beforeClass = 'patch-remove-line'; |
| b69ab31 | | | 43 | afterClass = 'patch-add-line'; |
| b69ab31 | | | 44 | break; |
| b69ab31 | | | 45 | case 'add': |
| b69ab31 | | | 46 | beforeClass = undefined; |
| b69ab31 | | | 47 | afterClass = 'patch-add-line'; |
| b69ab31 | | | 48 | break; |
| b69ab31 | | | 49 | case 'common': |
| b69ab31 | | | 50 | beforeClass = undefined; |
| b69ab31 | | | 51 | afterClass = undefined; |
| b69ab31 | | | 52 | break; |
| b69ab31 | | | 53 | case 'expanded': |
| b69ab31 | | | 54 | beforeClass = 'patch-expanded'; |
| b69ab31 | | | 55 | afterClass = 'patch-expanded'; |
| b69ab31 | | | 56 | break; |
| b69ab31 | | | 57 | } |
| b69ab31 | | | 58 | |
| b69ab31 | | | 59 | // Note that 'expanded' is a special case of 'common' where it is code that is |
| b69ab31 | | | 60 | // common to both sides of the diff, but was previously displayed as |
| b69ab31 | | | 61 | // collapsed. For whatever reason, GitHub does not make it possible to comment |
| b69ab31 | | | 62 | // on lines outside of the patch contents in PRs: |
| b69ab31 | | | 63 | // |
| b69ab31 | | | 64 | // https://github.com/isaacs/github/issues/1655 |
| b69ab31 | | | 65 | // |
| b69ab31 | | | 66 | // Even if you try to do so programmatically via the GraphQL API, it *still* |
| b69ab31 | | | 67 | // doesn't work, so this seems to be some quirk in the underlying data model. |
| b69ab31 | | | 68 | const canComment = rowType !== 'expanded'; |
| b69ab31 | | | 69 | |
| b69ab31 | | | 70 | return [ |
| b69ab31 | | | 71 | LineNumber({ |
| b69ab31 | | | 72 | className: beforeClass, |
| b69ab31 | | | 73 | lineNumber: beforeLineNumber, |
| b69ab31 | | | 74 | path, |
| b69ab31 | | | 75 | side: 'LEFT', |
| b69ab31 | | | 76 | column: 0, |
| b69ab31 | | | 77 | canComment, |
| b69ab31 | | | 78 | }), |
| b69ab31 | | | 79 | <td data-column={unified ? 2 : 1} className={beforeClass}> |
| b69ab31 | | | 80 | {before} |
| b69ab31 | | | 81 | </td>, |
| b69ab31 | | | 82 | LineNumber({ |
| b69ab31 | | | 83 | className: afterClass, |
| b69ab31 | | | 84 | lineNumber: afterLineNumber, |
| b69ab31 | | | 85 | path, |
| b69ab31 | | | 86 | side: 'RIGHT', |
| b69ab31 | | | 87 | column: unified ? 1 : 2, |
| b69ab31 | | | 88 | canComment, |
| b69ab31 | | | 89 | openFileToLine, // opening to a line number only makes sense on the "right" comparison side |
| b69ab31 | | | 90 | }), |
| b69ab31 | | | 91 | <td data-column={unified ? 2 : 3} className={afterClass}> |
| b69ab31 | | | 92 | {after} |
| b69ab31 | | | 93 | </td>, |
| b69ab31 | | | 94 | ]; |
| b69ab31 | | | 95 | } |
| b69ab31 | | | 96 | |
| b69ab31 | | | 97 | type LineNumberProps = { |
| b69ab31 | | | 98 | className?: string; |
| b69ab31 | | | 99 | lineNumber: number | null; |
| b69ab31 | | | 100 | path: string; |
| b69ab31 | | | 101 | side: 'LEFT' | 'RIGHT'; |
| b69ab31 | | | 102 | column: number; |
| b69ab31 | | | 103 | canComment: boolean; |
| b69ab31 | | | 104 | openFileToLine?: (lineNumber: OneIndexedLineNumber) => unknown; |
| b69ab31 | | | 105 | }; |
| b69ab31 | | | 106 | |
| b69ab31 | | | 107 | function LineNumber({ |
| b69ab31 | | | 108 | className, |
| b69ab31 | | | 109 | lineNumber, |
| b69ab31 | | | 110 | path, |
| b69ab31 | | | 111 | side, |
| b69ab31 | | | 112 | column, |
| b69ab31 | | | 113 | openFileToLine, |
| b69ab31 | | | 114 | }: LineNumberProps): JSX.Element { |
| b69ab31 | | | 115 | const clickableLineNumber = openFileToLine != null && lineNumber != null; |
| b69ab31 | | | 116 | const extraClassName = |
| b69ab31 | | | 117 | (className != null ? ` ${className}-number` : '') + (clickableLineNumber ? ' clickable' : ''); |
| b69ab31 | | | 118 | return ( |
| b69ab31 | | | 119 | <td |
| b69ab31 | | | 120 | className={`lineNumber${extraClassName} lineNumber-${side}`} |
| b69ab31 | | | 121 | data-line-number={lineNumber} |
| b69ab31 | | | 122 | data-path={path} |
| b69ab31 | | | 123 | data-side={side} |
| b69ab31 | | | 124 | data-column={column} |
| b69ab31 | | | 125 | onClick={clickableLineNumber ? () => openFileToLine(lineNumber) : undefined}> |
| b69ab31 | | | 126 | {lineNumber} |
| b69ab31 | | | 127 | </td> |
| b69ab31 | | | 128 | ); |
| b69ab31 | | | 129 | } |
| b69ab31 | | | 130 | |
| b69ab31 | | | 131 | export function BlankLineNumber({before}: ExclusiveOr<{before: true}, {after: true}>) { |
| b69ab31 | | | 132 | return ( |
| b69ab31 | | | 133 | <td |
| b69ab31 | | | 134 | className={ |
| b69ab31 | | | 135 | before |
| b69ab31 | | | 136 | ? 'patch-remove-line-number lineNumber lineNumber-LEFT' |
| b69ab31 | | | 137 | : 'patch-add-line-number lineNumber lineNumber-RIGHT' |
| b69ab31 | | | 138 | } |
| b69ab31 | | | 139 | /> |
| b69ab31 | | | 140 | ); |
| b69ab31 | | | 141 | } |