Skip to content

Commit

Permalink
feat(page.tsx): add tab navigation to occurrence page for easier acce…
Browse files Browse the repository at this point in the history
…ss to different occurrence details

feat(CounterLabel.tsx): create CounterLabel component to display occurrence count with color coding
refactor(NoticesTable.tsx): import CounterLabel from new location and remove unused import statement

refactor: rename OccurrenceCounterLabel to CounterLabel for consistency with other components
feat: add Backtrace component to display backtrace information in occurrence details
feat: add BacktraceLine component to display linked file path in backtrace
feat: add Context component to display context information in occurrence details
feat: add Environment component to display environment information in occurrence details

feat(occurrence): add Params, Session and Toolbox components to display occurrence data and add ToolboxAI component to interact with an AI

The Params, Session and Toolbox components were added to display occurrence data in the UI. The ToolboxAI component was added to interact with an AI and display its responses in real-time. The Toolbox component was also added to contain the ToolboxAI component and any other future components that may be added.
  • Loading branch information
masterkain committed May 17, 2023
1 parent 9ca0ca9 commit 69b52e0
Show file tree
Hide file tree
Showing 14 changed files with 214 additions and 191 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
import OccurrenceCard from '@/components/OccurrenceCard';
import EnvironmentLabel from '@/components/EnvironmentLabel';
import ProjectHeader from '@/components/ProjectHeader';
import SidebarDesktop from '@/components/SidebarDesktop';
import classNames from '@/lib/classNames';
import { prisma } from '@/lib/db';
import { OccurrenceTabKeys } from '@/types/airbroke';
import Link from 'next/link';
import { FaCarCrash, FaRegAddressBook, FaToolbox } from 'react-icons/fa';
import { HiCubeTransparent } from 'react-icons/hi';
import { MdOutlineWebhook } from 'react-icons/md';
import { SiCodefactor } from 'react-icons/si';
import { TbCubeUnfolded } from 'react-icons/tb';

import Backtrace from '@/components/occurrence/Backtrace';
import Context from '@/components/occurrence/Context';
import Environment from '@/components/occurrence/Environment';
import Params from '@/components/occurrence/Params';
import Session from '@/components/occurrence/Session';
import Toolbox from '@/components/occurrence/Toolbox';

export default async function Occurrence({
params,
Expand All @@ -12,7 +26,7 @@ export default async function Occurrence({
searchParams: Record<string, string>;
}) {
const tabKeys: OccurrenceTabKeys[] = ['backtrace', 'context', 'environment', 'session', 'params', 'toolbox'];
const tab = tabKeys.includes(searchParams.tab as OccurrenceTabKeys)
const currentTab = tabKeys.includes(searchParams.tab as OccurrenceTabKeys)
? (searchParams.tab as OccurrenceTabKeys)
: 'backtrace';

Expand Down Expand Up @@ -41,6 +55,19 @@ export default async function Occurrence({

const { notice, ...occurrence } = occurrenceWithRelations;
const { project, ...noticeData } = notice;

const tabs = [
{ id: 'backtrace', name: 'Backtrace', current: currentTab === 'backtrace', icon: SiCodefactor },
{ id: 'context', name: 'Context', current: currentTab === 'context', icon: HiCubeTransparent },
{ id: 'environment', name: 'Environment', current: currentTab === 'environment', icon: TbCubeUnfolded },
{ id: 'session', name: 'Session', current: currentTab === 'session', icon: FaRegAddressBook },
{ id: 'params', name: 'Params', current: currentTab === 'params', icon: MdOutlineWebhook },
{ id: 'toolbox', name: 'Toolbox', current: currentTab === 'toolbox', icon: FaToolbox },
].map((tab) => ({
...tab,
href: `/projects/${project.id}/notices/${notice.id}/occurrences/${occurrence.id}?tab=${tab.id}`,
}));

return (
<>
{/* @ts-expect-error Server Component */}
Expand All @@ -51,7 +78,73 @@ export default async function Occurrence({
<ProjectHeader project={project} />
</div>

<OccurrenceCard notice={notice} occurrence={occurrence} project={project} currentTab={tab} />
<div className="pb-8">
<div className="px-4 py-4 sm:px-6 lg:px-8">
<div className="sm:hidden">
<label htmlFor="tabs" className="sr-only">
Select a tab
</label>
<select
name="tabs"
className="block w-full rounded-md border-gray-300 focus:border-indigo-500 focus:ring-indigo-500"
defaultValue={currentTab}
>
{tabs.map((tab) => (
<option key={tab.name}>{tab.name}</option>
))}
</select>
</div>
<div className="hidden sm:block">
<nav className="flex space-x-4" aria-label="Tabs">
{tabs.map((tab) => (
<Link
key={tab.id}
href={tab.href}
className={classNames(
tab.current
? 'bg-indigo-500 text-indigo-200 '
: 'bg-indigo-400/10 text-indigo-400 hover:bg-indigo-500 hover:text-indigo-200',
'inline-flex items-center gap-x-1.5 rounded-md px-3 py-2 text-sm font-medium ring-1 ring-indigo-400/30 transition-colors duration-200 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-500'
)}
aria-current={tab.current ? 'page' : undefined}
>
<tab.icon className="-ml-0.5 h-5 w-5 text-indigo-400" aria-hidden="true" />
{tab.name}
</Link>
))}
</nav>
</div>
</div>

<div className="px-4 pb-4 sm:px-6 lg:px-8">
<div className="rounded-md bg-gray-900 p-4 shadow-md">
<div className="flex">
<div className="flex-shrink-0">
<FaCarCrash className="h-5 w-5 text-indigo-400" aria-hidden="true" />
</div>
<div className="ml-3">
<div className="flex items-center">
<h3 className="mr-3 text-sm font-semibold text-indigo-400">
<Link href={`/projects/${project.id}/notices/${notice.id}/occurrences`}>{notice.kind}</Link>
</h3>
<EnvironmentLabel env={notice.env} />
</div>
<div className="mt-2 text-sm text-indigo-200">
<p>{occurrence.message}</p>
</div>
</div>
<div className="ml-3"></div>
</div>
</div>
</div>

{currentTab === 'backtrace' && <Backtrace occurrence={occurrence} project={project} />}
{currentTab === 'context' && <Context occurrence={occurrence} />}
{currentTab === 'environment' && <Environment occurrence={occurrence} />}
{currentTab === 'session' && <Session occurrence={occurrence} />}
{currentTab === 'params' && <Params occurrence={occurrence} />}
{currentTab === 'toolbox' && <Toolbox occurrence={occurrence} />}
</div>
</main>
</>
);
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion components/NoticesTable.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { notice, project } from '@prisma/client';
import Link from 'next/link';
import OccurrenceCounterLabel from './CounterLabel';
import CustomTimeAgo from './CustomTimeAgo';
import EnvironmentLabel from './EnvironmentLabel';
import OccurrenceCounterLabel from './OccurrenceCounterLabel';

export default function NoticesTable({ project, notices }: { project: project; notices: notice[] }) {
return (
Expand Down
184 changes: 0 additions & 184 deletions components/OccurrenceCard.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion components/OccurrencesTable.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { notice, occurrence, project } from '@prisma/client';
import Link from 'next/link';
import OccurrenceCounterLabel from './CounterLabel';
import CustomTimeAgo from './CustomTimeAgo';
import EnvironmentLabel from './EnvironmentLabel';
import OccurrenceCounterLabel from './OccurrenceCounterLabel';

export default function OccurrencesTable({
project,
Expand Down
2 changes: 1 addition & 1 deletion components/ProjectsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { composeRepoUrl } from '@/lib/gitProvider';
import { project } from '@prisma/client';
import Link from 'next/link';
import { FaGithub } from 'react-icons/fa';
import OccurrenceCounterLabel from './OccurrenceCounterLabel';
import OccurrenceCounterLabel from './CounterLabel';

export default function ProjectsTable({ projects }: { projects: project[] }) {
const statuses = {
Expand Down
38 changes: 38 additions & 0 deletions components/occurrence/Backtrace.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import classNames from '@/lib/classNames';
import { BacktraceItem } from '@/types/airbroke';
import { Prisma, occurrence, project } from '@prisma/client';
import LinkedBacktraceLine from './BacktraceLine';

function isBacktraceItem(item: any): item is BacktraceItem {
return item && typeof item.file === 'string' && typeof item.line === 'number' && typeof item.function === 'string';
}

export default function Backtrace({ occurrence, project }: { occurrence: occurrence; project: project }) {
return (
<>
{occurrence.backtrace && typeof occurrence.backtrace === 'object' && Array.isArray(occurrence.backtrace) && (
<div className="px-4 sm:px-6 lg:px-8">
{(occurrence.backtrace as Prisma.JsonArray).map(
(trace, index) =>
isBacktraceItem(trace) && (
<div key={index} className="flex flex-row flex-wrap justify-start pb-1 font-mono text-xs">
<p
className={classNames(
trace.file.includes('PROJECT_ROOT') ? 'font-semibold' : '',
'text-xs text-gray-400'
)}
>
<LinkedBacktraceLine file={trace.file} line={trace.line} project={project} />
</p>
<p className="mx-1 text-gray-400">:</p>
<p className="text-xs font-semibold text-indigo-400">{trace.line}</p>
<p className="mx-1 text-gray-400"></p>
<p className="text-xs font-semibold text-red-600">{trace.function}</p>
</div>
)
)}
</div>
)}
</>
);
}
File renamed without changes.
Loading

0 comments on commit 69b52e0

Please sign in to comment.