|
1 | | -import { useCallback, useMemo, useState } from "react"; |
2 | | -import { FileHeader, PierreDiffViewer } from "@/components/chapter"; |
3 | | -import { |
4 | | - type AnnotatedLineRef, |
5 | | - DIFF_SIDE, |
6 | | - FILE_STATUS, |
7 | | - type LineRef, |
8 | | - type PullRequestFile, |
9 | | -} from "@/lib/diff-types"; |
10 | | -import { DiffSettingsProvider } from "@/lib/use-diff-settings"; |
11 | | - |
12 | | -const SAMPLE_PATCH = `diff --git a/src/greet.ts b/src/greet.ts |
13 | | -index 1111111..2222222 100644 |
14 | | ---- a/src/greet.ts |
15 | | -+++ b/src/greet.ts |
16 | | -@@ -1,3 +1,6 @@ |
17 | | --export function greet(name: string) { |
18 | | -- return "Hello, " + name + "!"; |
19 | | -+export function greet(name: string): string { |
20 | | -+ if (!name) { |
21 | | -+ throw new Error("name is required"); |
22 | | -+ } |
23 | | -+ return \`Hello, \${name}!\`; |
24 | | - } |
25 | | -`; |
26 | | - |
27 | | -const SAMPLE_FILE: PullRequestFile = { |
28 | | - path: "src/greet.ts", |
29 | | - filename: "greet.ts", |
30 | | - status: FILE_STATUS.MODIFIED, |
31 | | - additions: 5, |
32 | | - deletions: 2, |
33 | | - hunks: [], |
34 | | - patch: SAMPLE_PATCH, |
35 | | -}; |
36 | | - |
37 | | -const KEY_CHANGE_ID = "kc-1"; |
38 | | - |
39 | | -const FIXTURE_LINE_REFS: AnnotatedLineRef[] = [ |
40 | | - { |
41 | | - keyChangeId: KEY_CHANGE_ID, |
42 | | - filePath: SAMPLE_FILE.path, |
43 | | - side: DIFF_SIDE.ADDITIONS, |
44 | | - startLine: 2, |
45 | | - endLine: 4, |
46 | | - }, |
47 | | -]; |
48 | | - |
49 | | -const ALL_LINE_REFS_BY_FILE: Map<string, AnnotatedLineRef[]> = new Map([ |
50 | | - [SAMPLE_FILE.path, FIXTURE_LINE_REFS], |
51 | | -]); |
52 | | - |
53 | | -function ChapterFixture() { |
54 | | - const [isCollapsed, setIsCollapsed] = useState(false); |
55 | | - const [isExpanded, setIsExpanded] = useState(false); |
56 | | - const [isViewed, setIsViewed] = useState(false); |
57 | | - const [checkedKeyChangeIds, setCheckedKeyChangeIds] = useState<Set<string>>(new Set()); |
58 | | - const [focusedKeyChangeId, setFocusedKeyChangeId] = useState<string | null>(null); |
59 | | - |
60 | | - const focusedLineRefsByFile = useMemo<Map<string, LineRef[]> | null>(() => { |
61 | | - if (focusedKeyChangeId !== KEY_CHANGE_ID) return null; |
62 | | - return new Map([ |
63 | | - [ |
64 | | - SAMPLE_FILE.path, |
65 | | - FIXTURE_LINE_REFS.map( |
66 | | - (ref): LineRef => ({ |
67 | | - filePath: ref.filePath, |
68 | | - side: ref.side, |
69 | | - startLine: ref.startLine, |
70 | | - endLine: ref.endLine, |
71 | | - }), |
72 | | - ), |
73 | | - ], |
74 | | - ]); |
75 | | - }, [focusedKeyChangeId]); |
76 | | - |
77 | | - const isKeyChangeChecked = useCallback( |
78 | | - (id: string) => checkedKeyChangeIds.has(id), |
79 | | - [checkedKeyChangeIds], |
80 | | - ); |
81 | | - |
82 | | - const onMarkKeyChangeChecked = useCallback((id: string) => { |
83 | | - setCheckedKeyChangeIds((prev) => { |
84 | | - if (prev.has(id)) return prev; |
85 | | - const next = new Set(prev); |
86 | | - next.add(id); |
87 | | - return next; |
88 | | - }); |
89 | | - }, []); |
90 | | - |
91 | | - const onUnmarkKeyChangeChecked = useCallback((id: string) => { |
92 | | - setCheckedKeyChangeIds((prev) => { |
93 | | - if (!prev.has(id)) return prev; |
94 | | - const next = new Set(prev); |
95 | | - next.delete(id); |
96 | | - return next; |
97 | | - }); |
98 | | - }, []); |
99 | | - |
100 | | - const onFocusKeyChange = useCallback((id: string | null) => setFocusedKeyChangeId(id), []); |
| 1 | +import { useHashRunId } from "@/lib/use-hash-run-id"; |
| 2 | +import { PullRequestLayout } from "@/routes/pull-request-layout"; |
101 | 3 |
|
| 4 | +function NoRunSelected() { |
102 | 5 | return ( |
103 | | - <div className="min-h-screen bg-background p-6 text-foreground"> |
104 | | - <div className="mx-auto max-w-4xl space-y-4"> |
105 | | - <h1 className="font-semibold text-2xl">Chapter UI fixture</h1> |
106 | | - <p className="text-muted-foreground text-sm"> |
107 | | - Hand-crafted prop data exercising the vendored chapter components. |
| 6 | + <div className="flex min-h-screen items-center justify-center bg-background p-6 text-foreground"> |
| 7 | + <div className="max-w-md text-center"> |
| 8 | + <h1 className="font-semibold text-lg">No run selected</h1> |
| 9 | + <p className="mt-2 text-muted-foreground text-sm"> |
| 10 | + The URL is missing a <code>#/runs/<runId></code> hash. Open the app via{" "} |
| 11 | + <code>stage-cli show <path></code>. |
108 | 12 | </p> |
109 | | - <div> |
110 | | - <FileHeader |
111 | | - file={SAMPLE_FILE} |
112 | | - isCollapsed={isCollapsed} |
113 | | - isExpanded={isExpanded} |
114 | | - isViewed={isViewed} |
115 | | - onToggle={() => setIsCollapsed((prev) => !prev)} |
116 | | - onToggleAll={() => setIsCollapsed((prev) => !prev)} |
117 | | - onToggleExpand={() => setIsExpanded((prev) => !prev)} |
118 | | - onComment={() => {}} |
119 | | - onToggleViewed={() => setIsViewed((prev) => !prev)} |
120 | | - /> |
121 | | - {!isCollapsed && ( |
122 | | - <PierreDiffViewer |
123 | | - patch={SAMPLE_PATCH} |
124 | | - filePath={SAMPLE_FILE.path} |
125 | | - expandUnchanged={isExpanded} |
126 | | - allLineRefsByFile={ALL_LINE_REFS_BY_FILE} |
127 | | - focusedLineRefsByFile={focusedLineRefsByFile} |
128 | | - focusedKeyChangeId={focusedKeyChangeId} |
129 | | - isKeyChangeChecked={isKeyChangeChecked} |
130 | | - onMarkKeyChangeChecked={onMarkKeyChangeChecked} |
131 | | - onUnmarkKeyChangeChecked={onUnmarkKeyChangeChecked} |
132 | | - onFocusKeyChange={onFocusKeyChange} |
133 | | - /> |
134 | | - )} |
135 | | - </div> |
136 | 13 | </div> |
137 | 14 | </div> |
138 | 15 | ); |
139 | 16 | } |
140 | 17 |
|
141 | 18 | export function App() { |
142 | | - return ( |
143 | | - <DiffSettingsProvider> |
144 | | - <ChapterFixture /> |
145 | | - </DiffSettingsProvider> |
146 | | - ); |
| 19 | + const runId = useHashRunId(); |
| 20 | + if (!runId) return <NoRunSelected />; |
| 21 | + return <PullRequestLayout runId={runId} />; |
147 | 22 | } |
0 commit comments