@reviewflow/ui 0.0.0-stage → 6.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +15 -0
- package/README.md +95 -2
- package/package.json +101 -3
- package/src/board/bucket-section.tsx +94 -0
- package/src/board/dataSource.ts +44 -0
- package/src/board/facts.ts +183 -0
- package/src/board/index.ts +12 -0
- package/src/board/pull-request-board.tsx +239 -0
- package/src/board/pull-request-row.tsx +181 -0
- package/src/components/branch-diff/diff-themes.ts +6 -0
- package/src/components/branch-diff/diff-worker-pool.tsx +12 -0
- package/src/components/branch-diff/diff-worker-pool.web.tsx +56 -0
- package/src/components/branch-diff/diff-worker.ts +7 -0
- package/src/components/branch-diff/use-collapsed-files.ts +49 -0
- package/src/components/branch-diff/use-diff-settings.tsx +97 -0
- package/src/components/branch-diff/whitespace-button.tsx +32 -0
- package/src/components/copyable-code-block.tsx +101 -0
- package/src/components/label-pill.tsx +84 -0
- package/src/components/link-in-row.ts +6 -0
- package/src/components/markdown-suggestion.tsx +60 -0
- package/src/components/markdown-text.tsx +1067 -0
- package/src/components/pull-request-actions-merge.tsx +341 -0
- package/src/components/pull-request-actions-review.tsx +218 -0
- package/src/components/pull-request-checks.tsx +86 -0
- package/src/components/pull-request-commit-files.ts +143 -0
- package/src/components/pull-request-commits.tsx +221 -0
- package/src/components/pull-request-conversation-card.tsx +220 -0
- package/src/components/pull-request-conversation-edit.tsx +147 -0
- package/src/components/pull-request-conversation-event.tsx +267 -0
- package/src/components/pull-request-conversation-person.tsx +28 -0
- package/src/components/pull-request-conversation-thread.tsx +158 -0
- package/src/components/pull-request-diff-annotations.tsx +443 -0
- package/src/components/pull-request-diff-collapse.ts +43 -0
- package/src/components/pull-request-diff-data.ts +174 -0
- package/src/components/pull-request-diff-impacts-summary.tsx +97 -0
- package/src/components/pull-request-diff-impacts.ts +45 -0
- package/src/components/pull-request-diff-jump.ts +87 -0
- package/src/components/pull-request-diff-lines.ts +103 -0
- package/src/components/pull-request-diff-overview.tsx +416 -0
- package/src/components/pull-request-diff-view.tsx +438 -0
- package/src/components/pull-request-diff-viewer.tsx +1374 -0
- package/src/components/pull-request-files.tsx +533 -0
- package/src/components/pull-request-markdown-input.tsx +91 -0
- package/src/components/pull-request-panel.tsx +1270 -0
- package/src/components/pull-request-part-notice.tsx +82 -0
- package/src/components/pull-request-reactions.tsx +178 -0
- package/src/components/pull-request-review.tsx +164 -0
- package/src/components/pull-request-revisions.tsx +273 -0
- package/src/components/pull-request-screen.tsx +299 -0
- package/src/components/pull-request-suggestion-actions.tsx +201 -0
- package/src/components/pull-request-timeline.tsx +270 -0
- package/src/components/repository-attachment-banner.tsx +42 -0
- package/src/components/scroll-parent.ts +50 -0
- package/src/css.d.ts +1 -0
- package/src/dataSource.ts +242 -0
- package/src/editor/alerts.ts +105 -0
- package/src/editor/code-editor.native.tsx +25 -0
- package/src/editor/code-editor.tsx +112 -0
- package/src/editor/codeEditorExtensions.ts +65 -0
- package/src/editor/codeHighlight.ts +71 -0
- package/src/editor/commands.ts +175 -0
- package/src/editor/decorations.ts +425 -0
- package/src/editor/editable-file.tsx +224 -0
- package/src/editor/emojiCompletion.ts +110 -0
- package/src/editor/extensions.ts +149 -0
- package/src/editor/frontmatter.ts +76 -0
- package/src/editor/inlineFormat.ts +114 -0
- package/src/editor/lineTypes.ts +55 -0
- package/src/editor/markdown-editor.css +511 -0
- package/src/editor/markdown-editor.native.tsx +29 -0
- package/src/editor/markdown-editor.tsx +295 -0
- package/src/editor/nodeClasses.ts +69 -0
- package/src/index.ts +75 -0
- package/src/markdown-github/flatten.ts +49 -0
- package/src/markdown-github/html-tokens.ts +93 -0
- package/src/markdown-github/pair-html.ts +354 -0
- package/src/markdown-github/safe-url.ts +15 -0
- package/src/markdown-github/table-columns.ts +23 -0
- package/src/markdown-github/toggle-task.ts +164 -0
- package/src/nativewind-env.d.ts +1 -0
- package/src/prStatus.ts +90 -0
- package/src/services/PullRequestDraftsProvider.tsx +179 -0
- package/src/services/PullRequestReviewDraftProvider.tsx +178 -0
- package/src/services/PullRequestSuggestionBatchProvider.tsx +112 -0
- package/src/services/emojify.ts +13 -0
- package/src/services/errorToMessage.ts +6 -0
- package/src/services/expiringDraftStore.ts +102 -0
- package/src/services/formatDataAge.ts +12 -0
- package/src/services/formatRelativeDate.ts +56 -0
- package/src/services/githubImages.tsx +33 -0
- package/src/services/isViewerAuthor.ts +7 -0
- package/src/slots.tsx +34 -0
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
DiffOmittedFile,
|
|
3
|
+
DiffStep,
|
|
4
|
+
DiffWhitespace,
|
|
5
|
+
PullRequestDiffResponse,
|
|
6
|
+
} from "@reviewflow/sdk";
|
|
7
|
+
import {
|
|
8
|
+
AccentScope,
|
|
9
|
+
Code,
|
|
10
|
+
IconButton,
|
|
11
|
+
IndeterminateCircularProgress,
|
|
12
|
+
IndeterminateLinearProgress,
|
|
13
|
+
InfoMessage,
|
|
14
|
+
Text,
|
|
15
|
+
View,
|
|
16
|
+
WarningMessage,
|
|
17
|
+
useCurrentBreakpointNameFiltered,
|
|
18
|
+
useCurrentMode,
|
|
19
|
+
} from "alouette";
|
|
20
|
+
import { ArrowsInLineVerticalRegularIcon } from "alouette-icons/phosphor-icons/ArrowsInLineVertical";
|
|
21
|
+
import { ArrowsOutLineVerticalRegularIcon } from "alouette-icons/phosphor-icons/ArrowsOutLineVertical";
|
|
22
|
+
import { ColumnsRegularIcon } from "alouette-icons/phosphor-icons/Columns";
|
|
23
|
+
import { RowsRegularIcon } from "alouette-icons/phosphor-icons/Rows";
|
|
24
|
+
import { TreeStructureRegularIcon } from "alouette-icons/phosphor-icons/TreeStructure";
|
|
25
|
+
import type { ComponentRef, ReactNode } from "react";
|
|
26
|
+
import {
|
|
27
|
+
Suspense,
|
|
28
|
+
lazy,
|
|
29
|
+
useDeferredValue,
|
|
30
|
+
useMemo,
|
|
31
|
+
useRef,
|
|
32
|
+
useState,
|
|
33
|
+
} from "react";
|
|
34
|
+
import type { PullRequestDiffRefusal } from "../dataSource.ts";
|
|
35
|
+
import { usePullRequestReviewDraft } from "../services/PullRequestReviewDraftProvider.tsx";
|
|
36
|
+
import { usePullRequestSlots } from "../slots.tsx";
|
|
37
|
+
import {
|
|
38
|
+
useDiffSettings,
|
|
39
|
+
useWhitespaceToggle,
|
|
40
|
+
} from "./branch-diff/use-diff-settings.tsx";
|
|
41
|
+
import { WhitespaceButton } from "./branch-diff/whitespace-button.tsx";
|
|
42
|
+
import { usePullRequestCollapse } from "./pull-request-diff-collapse.ts";
|
|
43
|
+
import type { PullRequestDiffTarget } from "./pull-request-diff-data.ts";
|
|
44
|
+
import {
|
|
45
|
+
useMissingCheckoutReason,
|
|
46
|
+
usePullRequestDiff,
|
|
47
|
+
usePullRequestImpacts,
|
|
48
|
+
usePullRequestReadingOrder,
|
|
49
|
+
} from "./pull-request-diff-data.ts";
|
|
50
|
+
import type { ImpactsStatus } from "./pull-request-diff-impacts.ts";
|
|
51
|
+
import {
|
|
52
|
+
DiffFileElementsContext,
|
|
53
|
+
createDiffFileElements,
|
|
54
|
+
} from "./pull-request-diff-jump.ts";
|
|
55
|
+
import type { Composer } from "./pull-request-diff-lines.ts";
|
|
56
|
+
import type { OverviewReadingOrderStatus } from "./pull-request-diff-overview.tsx";
|
|
57
|
+
import { PullRequestDiffOverview } from "./pull-request-diff-overview.tsx";
|
|
58
|
+
import type {
|
|
59
|
+
DiffStyle,
|
|
60
|
+
PullRequestDiffReview,
|
|
61
|
+
} from "./pull-request-diff-viewer.tsx";
|
|
62
|
+
import { cssVariableOf, scrollToTopOf } from "./scroll-parent.ts";
|
|
63
|
+
|
|
64
|
+
const PullRequestDiffViewer = lazy(
|
|
65
|
+
() => import("./pull-request-diff-viewer.tsx"),
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
const omissionLabel = (reason: DiffOmittedFile["reason"]): string => {
|
|
69
|
+
if (reason === "binary") return "binary";
|
|
70
|
+
if (reason === "tooLarge") return "too large";
|
|
71
|
+
if (reason === "whitespace") return "only whitespace changed";
|
|
72
|
+
return "over the diff budget";
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
function OmittedFiles({ omitted }: { omitted: DiffOmittedFile[] }): ReactNode {
|
|
76
|
+
if (omitted.length === 0) return null;
|
|
77
|
+
return (
|
|
78
|
+
<View className="gap-xxs">
|
|
79
|
+
<Text className="text-xs font-body-bold text-muted">
|
|
80
|
+
{`Left out (${String(omitted.length)})`}
|
|
81
|
+
</Text>
|
|
82
|
+
{omitted.map(({ path, reason }) => (
|
|
83
|
+
<View key={path} className="flex-row flex-wrap items-center gap-xs">
|
|
84
|
+
<Code className="text-xs">{path}</Code>
|
|
85
|
+
<Text className="text-xs text-muted">{omissionLabel(reason)}</Text>
|
|
86
|
+
</View>
|
|
87
|
+
))}
|
|
88
|
+
</View>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
interface DiffSourceProps {
|
|
93
|
+
diff: PullRequestDiffResponse;
|
|
94
|
+
asked: DiffWhitespace;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Said only when git could have answered and did not, or when GitHub could not
|
|
99
|
+
* hide whitespace as asked: a silent fallback hides a broken fetch, and a
|
|
100
|
+
* reindented file read as hidden would be read as rewritten.
|
|
101
|
+
*/
|
|
102
|
+
function DiffSource({ diff, asked }: DiffSourceProps): ReactNode {
|
|
103
|
+
const fallback =
|
|
104
|
+
diff.source === "git" || diff.fallbackReason === null
|
|
105
|
+
? null
|
|
106
|
+
: `Read from GitHub: local git could not (${diff.fallbackReason}).`;
|
|
107
|
+
const whitespace =
|
|
108
|
+
asked === "hide" && diff.whitespace === "show"
|
|
109
|
+
? "Whitespace changes are shown: GitHub's API cannot hide them."
|
|
110
|
+
: null;
|
|
111
|
+
if (fallback === null && whitespace === null) return null;
|
|
112
|
+
return (
|
|
113
|
+
<InfoMessage>
|
|
114
|
+
{[fallback, whitespace].filter((line) => line !== null).join(" ")}
|
|
115
|
+
</InfoMessage>
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const stepLabels: Record<DiffStep, string> = {
|
|
120
|
+
fetching: "fetching commits…",
|
|
121
|
+
diffing: "computing diff…",
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
/** What a read in progress is waiting on, when the source says: a large fetch takes tens of seconds. */
|
|
125
|
+
function DiffLoading({ step }: { step?: DiffStep | null }): ReactNode {
|
|
126
|
+
return (
|
|
127
|
+
<View className="items-center gap-xs py-xl">
|
|
128
|
+
<IndeterminateCircularProgress loading />
|
|
129
|
+
{step === null || step === undefined ? null : (
|
|
130
|
+
<Text className="text-sm text-muted">{stepLabels[step]}</Text>
|
|
131
|
+
)}
|
|
132
|
+
</View>
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* The source reads a diff from a local checkout only, and has none for this
|
|
138
|
+
* repository: says which file to edit and the line to add, rather than
|
|
139
|
+
* failing without a reason.
|
|
140
|
+
*/
|
|
141
|
+
export function DiffRefused({
|
|
142
|
+
refused,
|
|
143
|
+
action,
|
|
144
|
+
}: {
|
|
145
|
+
refused: PullRequestDiffRefusal;
|
|
146
|
+
/** overrides the `renderRepositoryAction` slot: a button to where the checkout is configured */
|
|
147
|
+
action?: ReactNode;
|
|
148
|
+
}): ReactNode {
|
|
149
|
+
const { reason, ownerRepo, configPath, detail } = refused;
|
|
150
|
+
const { renderRepositoryAction } = usePullRequestSlots();
|
|
151
|
+
const shownAction = action ?? renderRepositoryAction?.(ownerRepo);
|
|
152
|
+
return (
|
|
153
|
+
<WarningMessage>
|
|
154
|
+
<View className="gap-xs">
|
|
155
|
+
<Text className="font-body-bold text-sm">
|
|
156
|
+
{reason === "notConfigured"
|
|
157
|
+
? `${ownerRepo} has no local checkout configured, so its diff is not read.`
|
|
158
|
+
: `The configured checkout of ${ownerRepo} cannot be used.`}
|
|
159
|
+
</Text>
|
|
160
|
+
<Text className="text-sm">{detail}</Text>
|
|
161
|
+
<Text className="text-sm">
|
|
162
|
+
{"Add the line below to "}
|
|
163
|
+
<Code className="text-sm">{configPath}</Code>, under "repos":
|
|
164
|
+
</Text>
|
|
165
|
+
<Code className="text-sm">{`"${ownerRepo}": "/path/to/checkout"`}</Code>
|
|
166
|
+
{shownAction === null || shownAction === undefined ? null : (
|
|
167
|
+
<View className="flex-row">{shownAction}</View>
|
|
168
|
+
)}
|
|
169
|
+
</View>
|
|
170
|
+
</WarningMessage>
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
interface PullRequestDiffViewProps {
|
|
175
|
+
range: PullRequestDiffTarget;
|
|
176
|
+
/** left of the toolbar: a scope switch, a counter */
|
|
177
|
+
toolbarStart?: ReactNode;
|
|
178
|
+
/** last in the toolbar: the action the diff is read for */
|
|
179
|
+
toolbarEnd?: ReactNode;
|
|
180
|
+
/** absent: read-only, no threads, no commenting */
|
|
181
|
+
review?: PullRequestDiffReview;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* One range of the pull request's diff with the toolbar every diff here has:
|
|
186
|
+
* split/unified, whitespace shown or hidden, open and close every file. Local
|
|
187
|
+
* git when the repository is here, GitHub's API otherwise
|
|
188
|
+
* (`PullRequestDiffResponse`).
|
|
189
|
+
*
|
|
190
|
+
* The toolbar sticks to the top of the scroll container, so what it carries
|
|
191
|
+
* stays in reach down a long diff; the file headers, sticky too, are pinned
|
|
192
|
+
* under it at its measured height rather than behind it. The loading bar is in
|
|
193
|
+
* it, laid over its bottom edge so its height never moves the headers.
|
|
194
|
+
*
|
|
195
|
+
* The viewer renders a deferred diff and is memoized: a toolbar press commits
|
|
196
|
+
* at once, and rendering every file of the next patch is interruptible work
|
|
197
|
+
* that happens after it, rather than a freeze before the press shows.
|
|
198
|
+
*
|
|
199
|
+
* Hiding whitespace is refused while a comment is being written: its line may
|
|
200
|
+
* leave the patch, and the comment with it.
|
|
201
|
+
*/
|
|
202
|
+
export function PullRequestDiffView({
|
|
203
|
+
range,
|
|
204
|
+
toolbarStart,
|
|
205
|
+
toolbarEnd,
|
|
206
|
+
review,
|
|
207
|
+
}: PullRequestDiffViewProps): ReactNode {
|
|
208
|
+
const [diffStyle, setDiffStyle] = useState<DiffStyle>("split");
|
|
209
|
+
const [toolbarHeight, setToolbarHeight] = useState(0);
|
|
210
|
+
const fileElements = useMemo(createDiffFileElements, []);
|
|
211
|
+
const highlightProbe = useRef<ComponentRef<typeof View>>(null);
|
|
212
|
+
// a JS breakpoint rather than `xl:` classes: the sticky offset is the measured toolbar's
|
|
213
|
+
const aside = useCurrentBreakpointNameFiltered(["base", "wide"]) === "wide";
|
|
214
|
+
const whitespace = useWhitespaceToggle();
|
|
215
|
+
const { diff, error, loading, step, refused } = usePullRequestDiff(
|
|
216
|
+
range,
|
|
217
|
+
whitespace.whitespace,
|
|
218
|
+
);
|
|
219
|
+
const shownDiff = useDeferredValue(diff);
|
|
220
|
+
const collapse = usePullRequestCollapse();
|
|
221
|
+
const draft = usePullRequestReviewDraft();
|
|
222
|
+
// a commit's composer; the pull request's lives with the draft, which pins the range
|
|
223
|
+
const [commitComposer, setCommitComposer] = useState<{
|
|
224
|
+
commit: string;
|
|
225
|
+
composer: Composer;
|
|
226
|
+
} | null>(null);
|
|
227
|
+
const shownCommit = review?.commitOid ?? review?.commitFiles?.oid ?? null;
|
|
228
|
+
// kept per commit: stepping to the next commit does not carry it onto its lines
|
|
229
|
+
const shownCommitComposer =
|
|
230
|
+
commitComposer?.commit === shownCommit ? commitComposer.composer : null;
|
|
231
|
+
const onCommitComposerChange = useMemo(
|
|
232
|
+
() =>
|
|
233
|
+
(composer: Composer | null): void => {
|
|
234
|
+
setCommitComposer(
|
|
235
|
+
composer === null || shownCommit === null
|
|
236
|
+
? null
|
|
237
|
+
: { commit: shownCommit, composer },
|
|
238
|
+
);
|
|
239
|
+
},
|
|
240
|
+
[shownCommit],
|
|
241
|
+
);
|
|
242
|
+
const composing =
|
|
243
|
+
review !== undefined &&
|
|
244
|
+
(shownCommitComposer !== null ||
|
|
245
|
+
(review.commitOid === undefined && draft.composer !== null));
|
|
246
|
+
const mode = useCurrentMode();
|
|
247
|
+
const { wordWrap, theme, fileOrder, setFileOrder } = useDiffSettings();
|
|
248
|
+
const missingCheckout = useMissingCheckoutReason(range);
|
|
249
|
+
const readingOrder = usePullRequestReadingOrder(
|
|
250
|
+
range,
|
|
251
|
+
missingCheckout === null,
|
|
252
|
+
);
|
|
253
|
+
const ordered =
|
|
254
|
+
readingOrder.available &&
|
|
255
|
+
missingCheckout === null &&
|
|
256
|
+
fileOrder === "reading";
|
|
257
|
+
const impacts = usePullRequestImpacts(range, missingCheckout === null);
|
|
258
|
+
const impactsStatus = ((): ImpactsStatus => {
|
|
259
|
+
if (impacts.value !== null) return "ready";
|
|
260
|
+
if (impacts.reading) return "reading";
|
|
261
|
+
if (impacts.error !== null) return "failed";
|
|
262
|
+
return "none";
|
|
263
|
+
})();
|
|
264
|
+
const overviewStatus = ((): OverviewReadingOrderStatus => {
|
|
265
|
+
if (readingOrder.value !== null) return "ready";
|
|
266
|
+
if (readingOrder.reading) return "reading";
|
|
267
|
+
if (readingOrder.error !== null) return "failed";
|
|
268
|
+
return "none";
|
|
269
|
+
})();
|
|
270
|
+
|
|
271
|
+
return (
|
|
272
|
+
<View
|
|
273
|
+
className={
|
|
274
|
+
aside && diffStyle === "split"
|
|
275
|
+
? "gap-m web:relative web:left-1/2 web:w-[min(100vw-3rem,1800px)] web:-translate-x-1/2"
|
|
276
|
+
: "gap-m"
|
|
277
|
+
}
|
|
278
|
+
>
|
|
279
|
+
<View
|
|
280
|
+
className="-mx-l flex-row flex-wrap items-center justify-between gap-xs bg-screen px-l py-sm web:sticky web:top-0 web:z-10"
|
|
281
|
+
onLayout={(event) => {
|
|
282
|
+
setToolbarHeight(event.nativeEvent.layout.height);
|
|
283
|
+
}}
|
|
284
|
+
>
|
|
285
|
+
{/* sized to the bar: a zero-height box under the sticky toolbar left
|
|
286
|
+
Chromium painting the faded bar on, at its last width */}
|
|
287
|
+
<View className="absolute inset-x-l bottom-0 h-0.5">
|
|
288
|
+
<IndeterminateLinearProgress
|
|
289
|
+
loading={
|
|
290
|
+
loading || (ordered && readingOrder.reading) || shownDiff !== diff
|
|
291
|
+
}
|
|
292
|
+
size="xs"
|
|
293
|
+
/>
|
|
294
|
+
</View>
|
|
295
|
+
<View className="flex-row flex-wrap items-center gap-sm">
|
|
296
|
+
{toolbarStart}
|
|
297
|
+
</View>
|
|
298
|
+
<View className="flex-row items-center gap-xs">
|
|
299
|
+
<IconButton
|
|
300
|
+
icon={
|
|
301
|
+
diffStyle === "split" ? (
|
|
302
|
+
<RowsRegularIcon />
|
|
303
|
+
) : (
|
|
304
|
+
<ColumnsRegularIcon />
|
|
305
|
+
)
|
|
306
|
+
}
|
|
307
|
+
size="sm"
|
|
308
|
+
aria-label={
|
|
309
|
+
diffStyle === "split" ? "Show unified diff" : "Show split diff"
|
|
310
|
+
}
|
|
311
|
+
onPress={() => {
|
|
312
|
+
setDiffStyle(diffStyle === "split" ? "unified" : "split");
|
|
313
|
+
}}
|
|
314
|
+
/>
|
|
315
|
+
{readingOrder.available ? (
|
|
316
|
+
<IconButton
|
|
317
|
+
icon={<TreeStructureRegularIcon />}
|
|
318
|
+
size="sm"
|
|
319
|
+
accent={ordered ? "brand" : "neutral"}
|
|
320
|
+
disabledReason={missingCheckout}
|
|
321
|
+
aria-label={
|
|
322
|
+
ordered
|
|
323
|
+
? "Order files by package"
|
|
324
|
+
: "Order files for reading (experimental)"
|
|
325
|
+
}
|
|
326
|
+
onPress={() => {
|
|
327
|
+
setFileOrder(ordered ? "packages" : "reading");
|
|
328
|
+
}}
|
|
329
|
+
/>
|
|
330
|
+
) : null}
|
|
331
|
+
<WhitespaceButton
|
|
332
|
+
whitespace={whitespace.whitespace}
|
|
333
|
+
disabledReason={
|
|
334
|
+
composing ? "Post or close the comment being written first" : null
|
|
335
|
+
}
|
|
336
|
+
onToggle={whitespace.toggle}
|
|
337
|
+
/>
|
|
338
|
+
<IconButton
|
|
339
|
+
icon={<ArrowsOutLineVerticalRegularIcon />}
|
|
340
|
+
size="sm"
|
|
341
|
+
aria-label="Open every file"
|
|
342
|
+
onPress={collapse.expandAll}
|
|
343
|
+
/>
|
|
344
|
+
<IconButton
|
|
345
|
+
icon={<ArrowsInLineVerticalRegularIcon />}
|
|
346
|
+
size="sm"
|
|
347
|
+
aria-label="Close every file"
|
|
348
|
+
onPress={collapse.collapseAll}
|
|
349
|
+
/>
|
|
350
|
+
{toolbarEnd}
|
|
351
|
+
</View>
|
|
352
|
+
</View>
|
|
353
|
+
{error === null ? null : <WarningMessage>{error}</WarningMessage>}
|
|
354
|
+
{ordered && readingOrder.error !== null ? (
|
|
355
|
+
<WarningMessage>
|
|
356
|
+
{`Files are in package order: the reading order failed (${readingOrder.error})`}
|
|
357
|
+
</WarningMessage>
|
|
358
|
+
) : null}
|
|
359
|
+
{refused === null ? null : <DiffRefused refused={refused} />}
|
|
360
|
+
{(() => {
|
|
361
|
+
if (shownDiff === null) {
|
|
362
|
+
if (refused !== null || error !== null) return null;
|
|
363
|
+
return <DiffLoading step={step} />;
|
|
364
|
+
}
|
|
365
|
+
return (
|
|
366
|
+
<View className="gap-m">
|
|
367
|
+
<DiffSource diff={shownDiff} asked={whitespace.whitespace} />
|
|
368
|
+
<View className={aside ? "flex-row items-start gap-xl" : "gap-l"}>
|
|
369
|
+
<View
|
|
370
|
+
className={
|
|
371
|
+
aside
|
|
372
|
+
? "w-[280px] shrink-0 web:sticky web:max-h-[calc(100vh-8rem)] web:overflow-y-auto"
|
|
373
|
+
: ""
|
|
374
|
+
}
|
|
375
|
+
style={aside ? { top: toolbarHeight } : undefined}
|
|
376
|
+
>
|
|
377
|
+
<PullRequestDiffOverview
|
|
378
|
+
groups={shownDiff.groups}
|
|
379
|
+
omitted={shownDiff.omitted}
|
|
380
|
+
readingOrder={readingOrder.value}
|
|
381
|
+
readingOrderStatus={overviewStatus}
|
|
382
|
+
impacts={impacts.value}
|
|
383
|
+
impactsStatus={impactsStatus}
|
|
384
|
+
displayOrder={ordered ? readingOrder.value : null}
|
|
385
|
+
aside={aside}
|
|
386
|
+
onFilePress={(path) => {
|
|
387
|
+
const element = fileElements.elementOf(path);
|
|
388
|
+
if (element === undefined) return;
|
|
389
|
+
scrollToTopOf(element, toolbarHeight);
|
|
390
|
+
const color = cssVariableOf(
|
|
391
|
+
highlightProbe.current,
|
|
392
|
+
"--color-enabled",
|
|
393
|
+
);
|
|
394
|
+
if (color !== "") fileElements.highlight(path, color);
|
|
395
|
+
}}
|
|
396
|
+
/>
|
|
397
|
+
{/* the file header is pierre's shadow DOM, which no accent
|
|
398
|
+
class reaches: the color is read here and handed to it */}
|
|
399
|
+
<AccentScope accent="info">
|
|
400
|
+
<View ref={highlightProbe} className="hidden" />
|
|
401
|
+
</AccentScope>
|
|
402
|
+
</View>
|
|
403
|
+
<View className="min-w-0 flex-1 gap-m">
|
|
404
|
+
<OmittedFiles omitted={shownDiff.omitted} />
|
|
405
|
+
{shownDiff.patch === "" ? (
|
|
406
|
+
<Text className="text-muted">no changes</Text>
|
|
407
|
+
) : (
|
|
408
|
+
<Suspense fallback={<DiffLoading />}>
|
|
409
|
+
<DiffFileElementsContext value={fileElements}>
|
|
410
|
+
<PullRequestDiffViewer
|
|
411
|
+
pullRequest={range}
|
|
412
|
+
patch={shownDiff.patch}
|
|
413
|
+
groups={shownDiff.groups}
|
|
414
|
+
readingOrder={ordered ? readingOrder.value : null}
|
|
415
|
+
impacts={impacts.value}
|
|
416
|
+
sides={shownDiff.sides}
|
|
417
|
+
whitespace={shownDiff.whitespace}
|
|
418
|
+
diffStyle={diffStyle}
|
|
419
|
+
theme={theme}
|
|
420
|
+
themeType={mode}
|
|
421
|
+
wordWrap={wordWrap}
|
|
422
|
+
stickyTop={toolbarHeight}
|
|
423
|
+
collapse={collapse}
|
|
424
|
+
review={review}
|
|
425
|
+
commitComposer={shownCommitComposer}
|
|
426
|
+
onCommitComposerChange={onCommitComposerChange}
|
|
427
|
+
/>
|
|
428
|
+
</DiffFileElementsContext>
|
|
429
|
+
</Suspense>
|
|
430
|
+
)}
|
|
431
|
+
</View>
|
|
432
|
+
</View>
|
|
433
|
+
</View>
|
|
434
|
+
);
|
|
435
|
+
})()}
|
|
436
|
+
</View>
|
|
437
|
+
);
|
|
438
|
+
}
|