Skip to content

Commit

Permalink
Add React Router v6, MemoryRouter, bump Sentry SDK
Browse files Browse the repository at this point in the history
  • Loading branch information
Lms24 committed Nov 13, 2023
1 parent 6d790b0 commit 5a22877
Show file tree
Hide file tree
Showing 15 changed files with 214 additions and 143 deletions.
1 change: 1 addition & 0 deletions packages/spotlight/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"postcss": "^8.4.28",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.18.0",
"sql-formatter": "^12.2.4",
"tailwindcss": "^3.3.3",
"usehooks-ts": "^2.9.1"
Expand Down
24 changes: 20 additions & 4 deletions packages/spotlight/src/components/Overview.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useState } from 'react';
import { MemoryRouter, Route, Routes } from 'react-router-dom';
import { useNavigation } from '~/lib/useNavigation';
import Tabs from './Tabs';

Expand Down Expand Up @@ -26,13 +27,28 @@ export default function Overview({ integrationData }: { integrationData: Record<
})
.flat();

const TabContent =
tabs.find(tab => tab.id === activeTab)?.content || (() => <p>This tab doesn't seem to display anything (yet).</p>);
const initalTab = tabs.length ? `/${tabs[0].id}` : '/no-tabs';

return (
<>
<Tabs tabs={tabs} />
<TabContent integrationData={integrationData} />
<MemoryRouter initialEntries={[initalTab]}>
<Tabs tabs={tabs} />
<Routes>
<Route path="/not-found" element={<p>not fount</p>} key={'not-found'}></Route>
{tabs.map(tab => {
const TabContent =
(tab.content && tab.content) || (() => <p>This tab doesn't seem to display anything (yet).</p>);

return (
<Route
path={`/${tab.id}/*`}
key={tab.id}
element={<TabContent integrationData={integrationData} key={tab.id} />}
></Route>
);
})}
</Routes>
</MemoryRouter>
</>
);
}
30 changes: 23 additions & 7 deletions packages/spotlight/src/components/Tabs.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
import { Link, useNavigate } from 'react-router-dom';
import { IntegrationTab } from '~/integrations/integration';
import classNames from '../lib/classNames';

export type Props = {
/**
* Array of tabs to display.
*/
tabs: IntegrationTab<unknown>[];

/**
* Whether the tabs are nested inside another tab.
* If `nested` is `true`, links will be set relative to the parent
* tab route instead of absolute to the root.
*/
nested?: boolean;
};

export default function Tabs({ tabs }: Props) {
export default function Tabs({ tabs, nested }: Props) {
const navigate = useNavigate();
return (
<div>
<div className="sm:hidden">
Expand All @@ -19,8 +31,11 @@ export default function Tabs({ tabs }: Props) {
className="block w-full rounded-md border-gray-300 py-2 pl-3 pr-10 text-base focus:border-indigo-500 focus:outline-none focus:ring-indigo-500 sm:text-sm"
defaultValue={tabs.find(tab => tab.active)?.title}
onChange={e => {
const activeTab = tabs[parseInt(e.target.value, 10)];
activeTab.onSelect && activeTab.onSelect();
const activeTab = tabs.find(tab => tab.id === e.target.value);
if (activeTab && activeTab.onSelect) {
activeTab.onSelect();
}
navigate(`${nested ? '' : '/'}${activeTab?.id || 'not-found'}`);
}}
>
{tabs.map((tab, tabIdx) => (
Expand All @@ -33,13 +48,14 @@ export default function Tabs({ tabs }: Props) {
<div className="hidden sm:block">
<nav className="-mb-px flex space-x-8 px-6" aria-label="Tabs">
{tabs.map(tab => (
<button
<Link
to={`${nested ? '' : '/'}${tab.id}`}
key={tab.id}
className={classNames(
tab.active
? 'border-indigo-200 text-indigo-100'
: 'border-transparent text-indigo-400 hover:border-indigo-400 hover:text-indigo-100',
'flex whitespace-nowrap border-b-2 py-3 px-2 -mx-2 text-sm font-medium',
'-mx-2 flex whitespace-nowrap border-b-2 px-2 py-3 text-sm font-medium',
)}
onClick={() => tab.onSelect && tab.onSelect()}
aria-current={tab.active ? 'page' : undefined}
Expand All @@ -49,13 +65,13 @@ export default function Tabs({ tabs }: Props) {
<span
className={classNames(
tab.active ? 'bg-indigo-100 text-indigo-600' : 'bg-indigo-700 text-indigo-200',
'ml-3 hidden rounded py-0.5 px-2.5 text-xs font-medium md:inline-block',
'ml-3 hidden rounded px-2.5 py-0.5 text-xs font-medium md:inline-block',
)}
>
{tab.count}
</span>
) : null}
</button>
</Link>
))}
</nav>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { useState } from 'react';
import Error, { ErrorTitle } from './Events/Error';
import EventContexts from './EventContexts';
import { Link, Outlet, Route, Routes, useNavigate, useParams } from 'react-router-dom';
import Tabs from '~/components/Tabs';
import useKeyPress from '~/lib/useKeyPress';
import PlatformIcon from './PlatformIcon';
import { useNavigation } from '~/lib/useNavigation';
import EventBreadcrumbs from './EventBreadcrumbs';
import { SentryEvent } from '~/types';
import Tabs from '~/components/Tabs';
import sentryDataCache from '../data/sentryDataCache';
import EventBreadcrumbs from './EventBreadcrumbs';
import EventContexts from './EventContexts';
import Error, { ErrorTitle } from './Events/Error';
import PlatformIcon from './PlatformIcon';

function renderEvent(event: SentryEvent) {
if ('exception' in event) return <Error event={event} />;
Expand All @@ -18,14 +19,28 @@ function renderEventTitle(event: SentryEvent) {
return 'Unknown Event';
}

export default function EventDetails({ event }: { event: SentryEvent }) {
const { setEventId, setTraceId, setSpanId } = useNavigation();

export default function EventDetails() {
const { eventId } = useParams();
const navigate = useNavigate();
const [activeTab, setActiveTab] = useState('details');

useKeyPress('Escape', () => {
setEventId(null);
});
useKeyPress(
'Escape',
() => {
navigate('..');
},
true,
);

if (!eventId) {
return <p>Unknown event id</p>;
}

const event = sentryDataCache.getEventById(eventId);

if (!event) {
return <p>Event not found</p>;
}

const tabs = [
{
Expand All @@ -51,30 +66,25 @@ export default function EventDetails({ event }: { event: SentryEvent }) {
const traceCtx = event.contexts?.trace;
return (
<>
<div className="px-6 py-4 flex gap-x-2 bg-indigo-950 items-center">
<div className="flex items-center gap-x-2 bg-indigo-950 px-6 py-4">
<PlatformIcon platform={event.platform} />
<h1 className="text-2xl max-w-full truncate flex-1">{renderEventTitle(event)}</h1>
<h1 className="max-w-full flex-1 truncate text-2xl">{renderEventTitle(event)}</h1>
{!!traceCtx && (
<div className="font-mono text-indigo-300">
<div>
T:{' '}
<button
className="cursor-pointer underline"
onClick={e => {
e.stopPropagation();
setTraceId(traceCtx.trace_id);
}}
>
<Link className="cursor-pointer underline" to={`/traces/${traceCtx.trace_id}`}>
{traceCtx.trace_id}
</button>
</Link>
</div>
<div>
S:{' '}
<button
className="cursor-pointer underline"
onClick={e => {
e.stopPropagation();
setSpanId(traceCtx.trace_id, traceCtx.span_id);
// setSpanId(traceCtx.trace_id, traceCtx.span_id);
console.log('TODO, route to trace');
}}
>
{traceCtx.span_id}
Expand All @@ -83,11 +93,15 @@ export default function EventDetails({ event }: { event: SentryEvent }) {
</div>
)}
</div>
<Tabs tabs={tabs} />
<div className="divide-indigo-500 flex-1 bg-indigo-950 px-6 py-4">
{activeTab === 'details' && renderEvent(event)}
{activeTab === 'breadcrumbs' && <EventBreadcrumbs event={event} />}
{activeTab === 'contexts' && <EventContexts event={event} />}
<Tabs tabs={tabs} nested={true} />
<div className="flex-1 divide-indigo-500 bg-indigo-950 px-6 py-4">
<Routes>
<Route path="breadcrumbs" element={<EventBreadcrumbs event={event} />} />
<Route path="contexts" element={<EventContexts event={event} />} />
{/* Default tab */}
<Route path="*" element={renderEvent(event)} />
</Routes>
<Outlet />
</div>
</>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useNavigation } from '~/lib/useNavigation';
import { Link } from 'react-router-dom';
import { SentryEvent } from '~/types';
import { useSentryEvents } from './../data/useSentryEvents';
import { ErrorSummary } from './Events/Error';
Expand All @@ -11,7 +11,6 @@ function renderEvent(event: SentryEvent) {
}

export default function EventList() {
const { setEventId } = useNavigation();
const events = useSentryEvents();

const matchingEvents = events.filter(e => e.type !== 'transaction');
Expand All @@ -21,18 +20,18 @@ export default function EventList() {
{matchingEvents.length !== 0 ? (
matchingEvents.map(e => {
return (
<div
<Link
className="flex cursor-pointer items-center gap-x-4 px-6 py-4 hover:bg-indigo-800"
key={e.event_id}
onClick={() => setEventId(e.event_id)}
to={e.event_id}
>
<PlatformIcon platform={e.platform} className="text-indigo-300" />
<div className="flex w-48 flex-col truncate font-mono text-indigo-300">
<span>{(e.event_id || '').substring(0, 8)}</span>
<TimeSince date={e.timestamp} />
</div>
<div className="flex-1">{renderEvent(e)}</div>
</div>
</Link>
);
})
) : (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,37 +1,42 @@
import { useParams } from 'react-router-dom';
import useKeyPress from '~/lib/useKeyPress';
import SpanDetails from './SpanDetails';
import SpanTree from './SpanTree';
import DateTime from './DateTime';
import PlatformIcon from './PlatformIcon';
import { useNavigation } from '~/lib/useNavigation';
import dataCache from '../data/sentryDataCache';
import { Trace } from '~/types';
import { getDuration } from '../utils/duration';
import DateTime from './DateTime';
import PlatformIcon from './PlatformIcon';
import SpanDetails from './SpanDetails';
import SpanTree from './SpanTree';

export default function TraceDetails({ trace }: { trace: Trace }) {
export default function TraceDetails() {
useKeyPress('Escape', () => {
setTraceId(null);
});

const { traceId } = useParams();
const { spanId, setTraceId } = useNavigation();

if (!traceId) {
return <p>Unknown trace id</p>;
}

const trace = dataCache.getTraceById(traceId);
const span = spanId ? dataCache.getSpanById(trace.trace_id, spanId) : undefined;

const startTimestamp = trace.start_timestamp;
const totalDuration = trace.timestamp - startTimestamp;

return (
<>
<div className="px-6 py-4 flex gap-x-2 bg-indigo-950 items-center">
<div className="flex items-center gap-x-2 bg-indigo-950 px-6 py-4">
<PlatformIcon platform={trace.rootTransaction?.platform} />
<h1 className="text-2xl max-w-full truncate flex-1">{trace.rootTransactionName}</h1>
<h1 className="max-w-full flex-1 truncate text-2xl">{trace.rootTransactionName}</h1>
<div className="font-mono text-indigo-300">
<div>T: {trace.trace_id}</div>
<div>S: {trace.span_id}</div>
</div>
</div>
<div className="px-6 py-4">
<div className="flex flex-1 items-center text-indigo-300 gap-x-1">
<div className="flex flex-1 items-center gap-x-1 text-indigo-300">
<div className="text-indigo-200">
<DateTime date={trace.start_timestamp} />
</div>
Expand All @@ -45,7 +50,7 @@ export default function TraceDetails({ trace }: { trace: Trace }) {
</span>
</div>
</div>
<div className="divide-indigo-500 flex-1 bg-indigo-950 px-6 py-4">
<div className="flex-1 divide-indigo-500 bg-indigo-950 px-6 py-4">
<SpanTree
traceContext={trace}
tree={trace.spanTree}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { Link } from 'react-router-dom';
import classNames from '~/lib/classNames';
import { useNavigation } from '~/lib/useNavigation';
import { useSentryTraces } from '../data/useSentryTraces';
import { getDuration } from '../utils/duration';
import PlatformIcon from './PlatformIcon';
import TimeSince from './TimeSince';

export default function TraceList() {
const traceList = useSentryTraces();
const { setTraceId } = useNavigation();

return (
<>
Expand All @@ -16,13 +15,10 @@ export default function TraceList() {
traceList.map(trace => {
const duration = getDuration(trace.start_timestamp, trace.timestamp);
return (
<div
<Link
className="flex cursor-pointer items-center gap-x-4 px-6 py-4 hover:bg-indigo-800"
key={trace.trace_id}
onClick={e => {
e.stopPropagation();
setTraceId(trace.trace_id);
}}
to={trace.trace_id}
>
<PlatformIcon platform={trace.rootTransaction?.platform} />

Expand All @@ -44,7 +40,7 @@ export default function TraceList() {
</div>
</div>
</div>
</div>
</Link>
);
})
) : (
Expand Down
Loading

0 comments on commit 5a22877

Please sign in to comment.