Skip to content

Commit 0ccac58

Browse files
authored
feat(breadcrumbs): Implement shared timeline component (getsentry#72874)
Adds the shared timeline component along with a stories file to inspect it in storybook. Currently unused, but will replace breadcrumbs with it in future PRs ![image](https://github.com/getsentry/sentry/assets/35509934/75248a10-8aba-4f00-9940-cb5a3d8360a9) ![image](https://github.com/getsentry/sentry/assets/35509934/cf2cb927-a3b8-49db-8853-7b7a4085ecc4) ![image](https://github.com/getsentry/sentry/assets/35509934/b46c6530-54e7-4975-8457-edea54c61e28)
1 parent 12bb4a9 commit 0ccac58

File tree

3 files changed

+476
-0
lines changed

3 files changed

+476
-0
lines changed
Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
1+
import {Fragment} from 'react';
2+
3+
import {CodeSnippet} from 'sentry/components/codeSnippet';
4+
import {StructuredData} from 'sentry/components/structuredEventData';
5+
import Timeline from 'sentry/components/timeline';
6+
import {
7+
IconClock,
8+
IconCursorArrow,
9+
IconDashboard,
10+
IconFire,
11+
IconSentry,
12+
IconSort,
13+
} from 'sentry/icons';
14+
import storyBook from 'sentry/stories/storyBook';
15+
16+
export default storyBook('Timeline (Updated 06/17/24)', story => {
17+
story('Usage', () => (
18+
<CodeSnippet language="js">
19+
import Timeline from 'sentry/components/timeline';
20+
</CodeSnippet>
21+
));
22+
23+
story('<Timeline.Text />', () => (
24+
<Fragment>
25+
<p>
26+
<code>{'<Timeline.Text />'}</code> can be used to easily format the children of
27+
<code>{'<Timeline.Item />'}</code>. It generally contains descriptive text.
28+
</p>
29+
<p>
30+
<CodeSnippet language="jsx">
31+
{`<Timeline.Item ...>
32+
<Timeline.Text>{someText}</Timeline.Text>
33+
</Timeline.Item>`}
34+
</CodeSnippet>
35+
</p>
36+
<h6>Example</h6>
37+
<Timeline.Item
38+
title={'SyntaxError'}
39+
icon={<IconFire size="xs" />}
40+
timeString={now.toISOString()}
41+
colorConfig={{
42+
primary: 'red400',
43+
secondary: 'red200',
44+
}}
45+
isActive
46+
>
47+
<Timeline.Text>This is a description of the error</Timeline.Text>
48+
</Timeline.Item>
49+
</Fragment>
50+
));
51+
52+
story('<Timeline.Data />', () => (
53+
<Fragment>
54+
<p>
55+
<code>{'<Timeline.Data />'}</code> is used to format the children of
56+
<code>{'<Timeline.Item />'}</code>. It generally contains code snippets or
57+
payloads.
58+
</p>
59+
<p>
60+
<CodeSnippet language="jsx">
61+
{`<Timeline.Item ...>
62+
<Timeline.Data>
63+
<StructuredData value={someJson} />
64+
</Timeline.Data>
65+
</Timeline.Item>`}
66+
</CodeSnippet>
67+
</p>
68+
<h6>Example</h6>
69+
<Timeline.Item
70+
title={'Navigation'}
71+
icon={<IconSort rotated size="xs" />}
72+
timeString={now.toISOString()}
73+
colorConfig={{
74+
primary: 'green400',
75+
secondary: 'green200',
76+
}}
77+
>
78+
<Timeline.Data>
79+
<StructuredData
80+
value={JSONPayload}
81+
depth={0}
82+
maxDefaultDepth={1}
83+
meta={undefined}
84+
withAnnotatedText
85+
withOnlyFormattedText
86+
/>
87+
</Timeline.Data>
88+
</Timeline.Item>
89+
</Fragment>
90+
));
91+
92+
story('<Timeline.Item />', () => (
93+
<Fragment>
94+
<p>
95+
<code>{'<Timeline.Item/>'}</code> contains each item to represent
96+
</p>
97+
<h6>Required Props</h6>
98+
<ul>
99+
<li>
100+
<code>icon</code> - Icon component to render alongside item. Size `xs`
101+
recommended.
102+
</li>
103+
<li>
104+
<code>timeString</code> - ISO time string detailing the moment the item happened
105+
</li>
106+
<li>
107+
<code>title</code> - The header to appear on the item
108+
</li>
109+
</ul>
110+
<h6>Optional Props</h6>
111+
<ul>
112+
<li>
113+
<code>startTimeString</code> - If provided, time will be displayed relative to
114+
start time.
115+
</li>
116+
<li>
117+
<code>colorConfig</code> - A mapping of colors to use for emphasizing the item
118+
</li>
119+
<li>
120+
<code>isActive</code> - If set to true, will display a border under the item
121+
</li>
122+
<li>
123+
<code>onClick</code> - React event handler for the entire item
124+
</li>
125+
<li>
126+
<code>onMouseEnter</code> - React event handler for the entire item
127+
</li>
128+
<li>
129+
<code>onMouseLeave</code> - React event handler for the entire item
130+
</li>
131+
</ul>
132+
<h6>Example</h6>
133+
<Timeline.Item
134+
title={'SyntaxError'}
135+
icon={<IconFire size="xs" />}
136+
timeString={now.toISOString()}
137+
colorConfig={{
138+
primary: 'red400',
139+
secondary: 'red200',
140+
}}
141+
/>
142+
<Timeline.Item
143+
title={'Active Item'}
144+
icon={<IconCursorArrow size="xs" />}
145+
timeString={now.toISOString()}
146+
colorConfig={{
147+
primary: 'blue400',
148+
secondary: 'blue200',
149+
}}
150+
isActive
151+
>
152+
<Timeline.Text>This is a description of the error</Timeline.Text>
153+
</Timeline.Item>
154+
<Timeline.Item
155+
title={'Data'}
156+
icon={<IconDashboard size="xs" />}
157+
timeString={now.toISOString()}
158+
colorConfig={{
159+
primary: 'pink400',
160+
secondary: 'pink200',
161+
}}
162+
>
163+
<Timeline.Data>
164+
<StructuredData
165+
value={JSONPayload}
166+
depth={0}
167+
maxDefaultDepth={1}
168+
meta={undefined}
169+
withAnnotatedText
170+
withOnlyFormattedText
171+
/>
172+
</Timeline.Data>
173+
</Timeline.Item>
174+
<Timeline.Item
175+
title={'Relative Event'}
176+
icon={<IconClock size="xs" />}
177+
timeString={now.toISOString()}
178+
startTimeString={before.toISOString()}
179+
colorConfig={{
180+
primary: 'purple400',
181+
secondary: 'purple200',
182+
}}
183+
>
184+
<Timeline.Text>This is a description of the error</Timeline.Text>
185+
</Timeline.Item>
186+
</Fragment>
187+
));
188+
189+
story('<Timeline.Container />', () => (
190+
<Fragment>
191+
<p>
192+
<code>{'<Timeline.Container />'}</code> expects to contain{' '}
193+
<code>{'<Timeline.Item />'}</code> components. Adds a vertical line behind the
194+
elements, even if the item is not marked 'isActive'.
195+
</p>
196+
<h6>Example</h6>
197+
<Timeline.Container>
198+
<Timeline.Item
199+
title={'Error'}
200+
icon={<IconFire size="xs" />}
201+
timeString={now.toISOString()}
202+
colorConfig={{
203+
primary: 'red400',
204+
secondary: 'red200',
205+
}}
206+
>
207+
<Timeline.Text>This is a description of the error</Timeline.Text>
208+
</Timeline.Item>
209+
210+
<Timeline.Item
211+
title={'HTTP'}
212+
icon={<IconSort rotated size="xs" />}
213+
timeString={now.toISOString()}
214+
colorConfig={{
215+
primary: 'green400',
216+
secondary: 'green200',
217+
}}
218+
>
219+
{' '}
220+
<Timeline.Data>
221+
<StructuredData
222+
value={JSONPayload}
223+
depth={0}
224+
maxDefaultDepth={1}
225+
meta={undefined}
226+
withAnnotatedText
227+
withOnlyFormattedText
228+
/>
229+
</Timeline.Data>
230+
</Timeline.Item>
231+
232+
<Timeline.Item
233+
title={'UI Click'}
234+
icon={<IconCursorArrow size="xs" />}
235+
timeString={now.toISOString()}
236+
colorConfig={{
237+
primary: 'blue400',
238+
secondary: 'blue200',
239+
}}
240+
>
241+
<Timeline.Text>{'div.abc123 > xyz > somethingsomething'}</Timeline.Text>
242+
</Timeline.Item>
243+
244+
<Timeline.Item
245+
title={'Sentry Event'}
246+
icon={<IconSentry size="xs" />}
247+
timeString={now.toISOString()}
248+
colorConfig={{
249+
primary: 'purple400',
250+
secondary: 'purple200',
251+
}}
252+
>
253+
<Timeline.Text>
254+
<a href="sentry.io">sentry.io</a>
255+
</Timeline.Text>
256+
</Timeline.Item>
257+
</Timeline.Container>
258+
</Fragment>
259+
));
260+
});
261+
262+
const JSONPayload: Record<string, any> = {
263+
logger: 'info',
264+
url: {
265+
addr: 'example.com/checkout',
266+
query: {isBetaUi: true},
267+
},
268+
user_id: 123,
269+
organizations: ['acme', 'xyz'],
270+
};
271+
272+
const now = new Date();
273+
const before = new Date('2024-06-15');

0 commit comments

Comments
 (0)