diff --git a/pkg/dashboard/frontend/src/components/apis/APIExplorer.tsx b/pkg/dashboard/frontend/src/components/apis/APIExplorer.tsx
index 9ee4f2c04..d2b36cff1 100644
--- a/pkg/dashboard/frontend/src/components/apis/APIExplorer.tsx
+++ b/pkg/dashboard/frontend/src/components/apis/APIExplorer.tsx
@@ -6,7 +6,6 @@ import type {
LocalStorageHistoryItem,
} from '../../types'
import {
- Select,
Badge,
Spinner,
Tabs,
@@ -43,6 +42,15 @@ import { APIMethodBadge } from './APIMethodBadge'
import { Button } from '../ui/button'
import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip'
import BreadCrumbs from '../layout/BreadCrumbs'
+import {
+ Select,
+ SelectContent,
+ SelectGroup,
+ SelectItem,
+ SelectLabel,
+ SelectTrigger,
+ SelectValue,
+} from '../ui/select'
const getTabCount = (rows: FieldRow[]) => {
if (!rows) return 0
@@ -391,26 +399,34 @@ const APIExplorer = () => {
/>
-
@@ -472,7 +488,7 @@ const APIExplorer = () => {
-
-
+
diff --git a/pkg/dashboard/frontend/src/components/apis/APIHistory.tsx b/pkg/dashboard/frontend/src/components/apis/APIHistory.tsx
index dd58a7ce2..73aa7b48a 100644
--- a/pkg/dashboard/frontend/src/components/apis/APIHistory.tsx
+++ b/pkg/dashboard/frontend/src/components/apis/APIHistory.tsx
@@ -1,14 +1,11 @@
-import type { ApiHistoryItem, Endpoint } from '../../types'
-import Badge from '../shared/Badge'
-import { formatJSON, getDateString } from '../../lib/utils'
-import { Disclosure } from '@headlessui/react'
-import { ChevronUpIcon } from '@heroicons/react/20/solid'
+import type { ApiHistoryItem } from '../../types'
+import { formatJSON } from '../../lib/utils'
import { useState } from 'react'
import { Tabs } from '../shared'
import CodeEditor from './CodeEditor'
import APIResponseContent from './APIResponseContent'
import TableGroup from '../shared/TableGroup'
-import { ScrollArea } from '../ui/scroll-area'
+import HistoryAccordion from '../shared/HistoryAccordion'
interface Props {
history: ApiHistoryItem[]
@@ -45,13 +42,14 @@ const APIHistory: React.FC
= ({ history, selectedRequest }) => {
}
return (
-
-
- {requestHistory.map((h, idx) => (
-
- ))}
-
-
+ ({
+ label: h.event.api + h.event.request.path,
+ time: h.time,
+ status: h.event?.response?.status,
+ content: ,
+ }))}
+ />
)
}
@@ -65,9 +63,8 @@ function isJSON(data: string | undefined) {
return true
}
-const ApiHistoryAccordion: React.FC = ({
- time,
- event: { api, request, response },
+const ApiHistoryAccordionContent: React.FC = ({
+ event: { request, response },
}) => {
const [tabIndex, setTabIndex] = useState(0)
@@ -78,116 +75,81 @@ const ApiHistoryAccordion: React.FC = ({
const jsonTabs = [...tabs, { name: 'Payload' }]
return (
-
- {({ open }) => (
- <>
-
-
-
- {response.status && (
-
- Status:
- {response.status}
-
- )}
-
- {api}
- {request.path}
-
-
-
-
{getDateString(time)}
-
+
+
+
+ {tabIndex === 0 && (
+
key && value)
+ .map(([key, value]) => [
+ key.toLowerCase(),
+ value.join(', '),
+ ]),
+ },
+ {
+ name: 'Response Headers',
+ rows: Object.entries(response.headers ?? [])
+ .filter(([key, value]) => key && value)
+ .map(([key, value]) => [key.toLowerCase(), value]),
+ },
+ ]}
+ />
+ )}
+ {tabIndex === 1 && (
+
-
-
-
-
-
-
- {tabIndex === 0 && (
-
key && value)
- .map(([key, value]) => [
- key.toLowerCase(),
- value.join(', '),
- ]),
- },
- {
- name: 'Response Headers',
- rows: Object.entries(response.headers ?? [])
- .filter(([key, value]) => key && value)
- .map(([key, value]) => [key.toLowerCase(), value]),
- },
- ]}
- />
- )}
- {tabIndex === 1 && (
-
+ )}
+ {tabIndex === 2 && (
+
+
+
Request Body
+
-
-
- {request.queryParams && (
-
key && value)
- .map(({ key, value }) => [key, value]),
- },
- ]}
- />
- )}
-
-
- )}
-
+ title="Request Body"
+ />
+
+
+ {request.queryParams && (
+
key && value)
+ .map(({ key, value }) => [key, value]),
+ },
+ ]}
+ />
+ )}
-
- >
- )}
-
+ )}
+
+
+
)
}
diff --git a/pkg/dashboard/frontend/src/components/apis/APIMenu.tsx b/pkg/dashboard/frontend/src/components/apis/APIMenu.tsx
index 5188a7c4d..c72da811f 100644
--- a/pkg/dashboard/frontend/src/components/apis/APIMenu.tsx
+++ b/pkg/dashboard/frontend/src/components/apis/APIMenu.tsx
@@ -1,10 +1,16 @@
-import { Menu, Transition } from '@headlessui/react'
-import { EllipsisHorizontalIcon } from '@heroicons/react/20/solid'
-import { Fragment } from 'react'
import type { Endpoint } from '../../types'
import { LOCAL_STORAGE_KEY } from './APIExplorer'
import { useHistory } from '../../lib/hooks/use-history'
-import { cn, formatJSON } from '@/lib/utils'
+import { formatJSON } from '@/lib/utils'
+import {
+ DropdownMenuGroup,
+ DropdownMenuItem,
+ DropdownMenuLabel,
+ DropdownMenuSeparator,
+} from '../ui/dropdown-menu'
+import TrashIcon from '@heroicons/react/24/outline/TrashIcon'
+import { ArrowDownOnSquareIcon } from '@heroicons/react/24/outline'
+import ResourceDropdownMenu from '../shared/ResourceDropdownMenu'
interface Props {
selected: Endpoint
@@ -44,53 +50,20 @@ const APIMenu: React.FC = ({ selected, onAfterClear }) => {
}
return (
-
+
+ API Menu
+
+
+
+
+ Export Spec
+
+
+
+ Clear History
+
+
+
)
}
diff --git a/pkg/dashboard/frontend/src/components/events/EventsExplorer.tsx b/pkg/dashboard/frontend/src/components/events/EventsExplorer.tsx
index 38b668edf..e314551fd 100644
--- a/pkg/dashboard/frontend/src/components/events/EventsExplorer.tsx
+++ b/pkg/dashboard/frontend/src/components/events/EventsExplorer.tsx
@@ -1,7 +1,7 @@
import { useEffect, useState } from 'react'
import { useWebSocket } from '../../lib/hooks/use-web-socket'
import type { APIResponse, EventHistoryItem, Schedule, Topic } from '@/types'
-import { Badge, Select, Spinner, Tabs, Loading } from '../shared'
+import { Badge, Spinner, Tabs, Loading } from '../shared'
import APIResponseContent from '../apis/APIResponseContent'
import {
fieldRowArrToHeaders,
@@ -24,6 +24,14 @@ import { capitalize } from 'radash'
import { Button } from '../ui/button'
import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip'
import BreadCrumbs from '../layout/BreadCrumbs'
+import {
+ Select,
+ SelectContent,
+ SelectGroup,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from '../ui/select'
interface Props {
workerType: 'schedules' | 'topics'
@@ -182,18 +190,28 @@ const EventsExplorer: React.FC = ({ workerType }) => {
{data![workerType] && (
(
-
- {w.name}
-
- )}
- />
+ value={selectedWorker.name}
+ onValueChange={(name) => {
+ setSelectedWorker(
+ data![workerType].find((b) => b.name === name),
+ )
+ }}
+ >
+
+
+
+
+
+ {data![workerType].map((worker) => (
+
+ {worker.name}
+
+ ))}
+
+
+
)}
diff --git a/pkg/dashboard/frontend/src/components/events/EventsHistory.tsx b/pkg/dashboard/frontend/src/components/events/EventsHistory.tsx
index 4ec1965f1..dc944bfda 100644
--- a/pkg/dashboard/frontend/src/components/events/EventsHistory.tsx
+++ b/pkg/dashboard/frontend/src/components/events/EventsHistory.tsx
@@ -4,12 +4,9 @@ import type {
Topic,
TopicHistoryItem,
} from '../../types'
-import Badge from '../shared/Badge'
-import { formatJSON, getDateString } from '../../lib/utils'
-import { Disclosure } from '@headlessui/react'
-import { ChevronUpIcon } from '@heroicons/react/20/solid'
+import { formatJSON } from '@/lib/utils'
import CodeEditor from '../apis/CodeEditor'
-import { ScrollArea } from '../ui/scroll-area'
+import HistoryAccordion from '../shared/HistoryAccordion'
interface Props {
history: EventHistoryItem[]
@@ -33,58 +30,21 @@ const EventsHistory: React.FC
= ({
return (
-
-
- {requestHistory.map((h, idx) => (
-
- ))}
-
-
-
- )
-}
+ {
+ let payload = ''
-const EventHistoryAccordion: React.FC<
- EventHistoryItem & Pick
-> = ({ event, time, workerType }) => {
- let payload = ''
+ if (workerType === 'topics') {
+ payload = (h.event as TopicHistoryItem['event']).payload
+ }
- if (workerType === 'topics') {
- payload = (event as TopicHistoryItem['event']).payload
- }
-
- const formattedPayload = payload ? formatJSON(payload) : ''
+ const formattedPayload = payload ? formatJSON(payload) : ''
- return (
-
- {({ open }) => (
- <>
-
-
-
-
- {event.success ? 'success' : 'failure'}
-
-
{event.name}
-
-
-
{getDateString(time)}
- {payload && (
-
- )}
-
-
-
-
- {formattedPayload && (
-
+ return {
+ label: h.event.name,
+ time: h.time,
+ success: Boolean(h.event.success),
+ content: formattedPayload ? (
Payload
@@ -96,11 +56,11 @@ const EventHistoryAccordion: React.FC<
/>
-
- )}
- >
- )}
-
+ ) : undefined,
+ }
+ })}
+ />
+
)
}
diff --git a/pkg/dashboard/frontend/src/components/events/EventsMenu.tsx b/pkg/dashboard/frontend/src/components/events/EventsMenu.tsx
index fbb093501..23a59d07e 100644
--- a/pkg/dashboard/frontend/src/components/events/EventsMenu.tsx
+++ b/pkg/dashboard/frontend/src/components/events/EventsMenu.tsx
@@ -1,8 +1,13 @@
-import { Menu, Transition } from '@headlessui/react'
-import { EllipsisHorizontalIcon } from '@heroicons/react/20/solid'
-import { cn } from '@/lib/utils'
-import { Fragment } from 'react'
+import { TrashIcon } from '@heroicons/react/20/solid'
+
import { useHistory } from '../../lib/hooks/use-history'
+import ResourceDropdownMenu from '../shared/ResourceDropdownMenu'
+import {
+ DropdownMenuGroup,
+ DropdownMenuItem,
+ DropdownMenuLabel,
+ DropdownMenuSeparator,
+} from '../ui/dropdown-menu'
interface Props {
storageKey: string
@@ -37,40 +42,18 @@ const EventsMenu: React.FC = ({
}
return (
-
+
+
+ {workerType} Menu
+
+
+
+
+
+ Clear History
+
+
+
)
}
diff --git a/pkg/dashboard/frontend/src/components/layout/AppLayout.tsx b/pkg/dashboard/frontend/src/components/layout/AppLayout.tsx
index 0cc185fe9..5dfe26d61 100644
--- a/pkg/dashboard/frontend/src/components/layout/AppLayout.tsx
+++ b/pkg/dashboard/frontend/src/components/layout/AppLayout.tsx
@@ -1,10 +1,4 @@
-import {
- Fragment,
- type PropsWithChildren,
- type ReactNode,
- useState,
-} from 'react'
-import { Dialog, Popover, Transition } from '@headlessui/react'
+import type { PropsWithChildren, ReactNode } from 'react'
import {
DocumentDuplicateIcon,
Bars3Icon,
@@ -12,7 +6,6 @@ import {
XMarkIcon,
ClockIcon,
ArchiveBoxIcon,
- CircleStackIcon,
MegaphoneIcon,
QuestionMarkCircleIcon,
PaperAirplaneIcon,
@@ -33,6 +26,8 @@ import { Button } from '../ui/button'
import { ExclamationCircleIcon } from '@heroicons/react/20/solid'
import { Alert, AlertDescription, AlertTitle } from '../ui/alert'
import { Spinner } from '../shared'
+import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover'
+import { Sheet, SheetContent, SheetTrigger } from '../ui/sheet'
const DiscordLogo: React.FC> = ({
className,
@@ -103,7 +98,6 @@ const AppLayout: React.FC = ({
routePath = '/',
}) => {
const { data, state } = useWebSocket()
- const [sidebarOpen, setSidebarOpen] = useState(false)
// remove trailing slash
routePath = routePath !== '/' ? routePath.replace(/\/$/, '') : routePath
@@ -149,140 +143,6 @@ const AppLayout: React.FC = ({
<>
-
-
-
@@ -344,14 +204,91 @@ const AppLayout: React.FC
= ({
-
+
+
+
+
+
+
+
+

+
+ {data?.projectName}
+
+
+
+
+
+
{/* Separator */}
= ({
/>
{data?.projectName && (
- {data.projectName}
/{' '}
+
+ {data.projectName}
+ {' '}
+
/{' '}