| 91 | |
| 92 | // A side-by-side diff of source code. |
| 93 | export function CodeDiffContainer(props: CodeDiffContainerProps) { |
| 94 | const {filePair, diffOptions, normalizeJSON} = props; |
| 95 | const [contents, setContents] = React.useState< |
| 96 | {before: string | null; after: string | null; diffOps: DiffRange[]} | undefined |
| 97 | >(); |
| 98 | |
| 99 | React.useEffect(() => { |
| 100 | // It would be more correct to set contents=undefined here to get a loading state, |
| 101 | // but this produces an unnecessary flash for rapid transitions. |
| 102 | const getDiff = async () => { |
| 103 | const response = await fetch(`/diff/${filePair.idx}`, { |
| 104 | method: 'POST', |
| 105 | headers: { |
| 106 | Accept: 'application/json', |
| 107 | 'Content-Type': 'application/json', |
| 108 | }, |
| 109 | body: JSON.stringify({ |
| 110 | options: gitDiffOptionsToFlags(diffOptions), |
| 111 | normalize_json: normalizeJSON, |
| 112 | }), |
| 113 | }); |
| 114 | return response.json() as Promise<DiffRange[]>; |
| 115 | }; |
| 116 | |
| 117 | const {a, b} = filePair; |
| 118 | // Do XHRs for the contents of both sides in parallel and fill in the diff. |
| 119 | // TODO: split these into three useEffects to avoid over-fetching when diff options change. |
| 120 | (async () => { |
| 121 | const [before, after, diffOps] = await Promise.all([ |
| 122 | getOrNull('a', a, normalizeJSON), |
| 123 | getOrNull('b', b, normalizeJSON), |
| 124 | getDiff(), |
| 125 | ]); |
| 126 | setContents({before, after, diffOps}); |
| 127 | })().catch((e: unknown) => { |
| 128 | alert('Unable to get diff!'); |
| 129 | console.error(e); |
| 130 | }); |
| 131 | }, [filePair, diffOptions, normalizeJSON]); |
| 132 | |
| 133 | const isEqualAfterNormalization = React.useMemo(() => { |
| 134 | return !filePair.no_changes && normalizeJSON && contents && contents.before == contents.after; |
| 135 | }, [contents, filePair.no_changes, normalizeJSON]); |
| 136 | |
| 137 | return ( |
| 138 | <div> |
| 139 | <div key={filePair.idx}> |
| 140 | {contents ? ( |
| 141 | <FileDiff |
| 142 | filePair={filePair} |
| 143 | contentsBefore={contents.before} |
| 144 | contentsAfter={contents.after} |
| 145 | diffOps={contents.diffOps} |
| 146 | isEqualAfterNormalization={!!isEqualAfterNormalization} |
| 147 | /> |
| 148 | ) : ( |
| 149 | 'Loading…' |
| 150 | )} |