Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(frontend): add global observability page #2156

Merged
25 changes: 18 additions & 7 deletions agenta-web/src/components/Filters/Filters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ type Props = {

const Filters: React.FC<Props> = ({filterData, columns, onApplyFilter, onClearFilter}) => {
const classes = useStyles()
const emptyFilter = [{key: "", operator: "", value: ""}] as Filter[]
const emptyFilter = [{key: "", operator: "", value: "", isPermanent: false}] as Filter[]

const [filter, setFilter] = useState<Filter[]>(emptyFilter)
const [filter, setFilter] = useState<Filter[]>(filterData || emptyFilter)
const [isFilterOpen, setIsFilterOpen] = useState(false)

useUpdateEffect(() => {
Expand Down Expand Up @@ -80,7 +80,7 @@ const Filters: React.FC<Props> = ({filterData, columns, onApplyFilter, onClearFi
value,
idx,
}: {
columnName: keyof Filter
columnName: Exclude<keyof Filter, "isPermanent">
value: any
idx: number
}) => {
Expand All @@ -94,17 +94,24 @@ const Filters: React.FC<Props> = ({filterData, columns, onApplyFilter, onClearFi
}

const addNestedFilter = () => {
setFilter([...filter, {key: "", operator: "", value: ""}])
setFilter([...filter, {key: "", operator: "", value: "", isPermanent: false}])
}

const clearFilter = () => {
setFilter(emptyFilter)
onClearFilter(emptyFilter)
const clearedFilters = filter.filter((f) => f.isPermanent)

if (JSON.stringify(clearedFilters) !== JSON.stringify(filter)) {
setFilter(clearedFilters)
onClearFilter(clearedFilters)
}
}

const applyFilter = () => {
const sanitizedFilters = filter.filter(({key, operator}) => key && operator)
onApplyFilter(sanitizedFilters)

if (JSON.stringify(sanitizedFilters) !== JSON.stringify(filterData)) {
onApplyFilter(sanitizedFilters)
}
setIsFilterOpen(false)
}

Expand Down Expand Up @@ -153,6 +160,7 @@ const Filters: React.FC<Props> = ({filterData, columns, onApplyFilter, onClearFi
}
value={item.key}
options={filteredColumns}
disabled={item.isPermanent}
/>

{item.key && (
Expand All @@ -173,12 +181,14 @@ const Filters: React.FC<Props> = ({filterData, columns, onApplyFilter, onClearFi
popupMatchSelectWidth={100}
value={item.operator}
options={filteredOperators}
disabled={item.isPermanent}
/>

<Input
placeholder="Keyword"
className="w-[220px]"
value={item.value}
disabled={item.isPermanent}
onChange={(e) =>
onFilterChange({
columnName: "value",
Expand All @@ -193,6 +203,7 @@ const Filters: React.FC<Props> = ({filterData, columns, onApplyFilter, onClearFi
<Button
type="link"
icon={<Trash size={14} />}
disabled={item.isPermanent}
onClick={() => onDeleteFilter(idx)}
/>
)}
Expand Down
17 changes: 12 additions & 5 deletions agenta-web/src/components/Sidebar/config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
SlackLogo,
Gear,
Dot,
TreeView,
} from "@phosphor-icons/react"
import {useAppsData} from "@/contexts/app.context"

Expand Down Expand Up @@ -67,6 +68,13 @@ export const useSidebarConfig = () => {
tooltip: "Create and manage testsets for evaluation purposes.",
link: `/apps/testsets`,
icon: <DatabaseOutlined />,
isHidden: apps.length === 0,
},
{
key: "app-observability-link",
title: "Observability",
link: `/observability`,
icon: <ChartLineUp />,
divider: true,
isHidden: apps.length === 0,
},
Expand Down Expand Up @@ -100,12 +108,11 @@ export const useSidebarConfig = () => {
icon: <ChartDonut size={16} />,
},
{
key: "app-observability-link",
title: "Observability",
icon: <ChartLineUp size={16} />,
key: "app-traces-link",
title: "Traces",
icon: <TreeView size={16} />,
isHidden: !appId && !recentlyVisitedAppId,
link: `/apps/${appId || recentlyVisitedAppId}/observability`,
cloudFeatureTooltip: "Observability available in Cloud/Enterprise editions only",
link: `/apps/${appId || recentlyVisitedAppId}/traces`,
},
{
key: "invite-teammate-link",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import EmptyComponent from "@/components/EmptyComponent"
import GenericDrawer from "@/components/GenericDrawer"
import {nodeTypeStyles} from "@/components/pages/observability/components/AvatarTreeContent"
import StatusRenderer from "@/components/pages/observability/components/StatusRenderer"
import TraceContent from "@/components/pages/observability/drawer/TraceContent"
import TraceHeader from "@/components/pages/observability/drawer/TraceHeader"
import TraceTree from "@/components/pages/observability/drawer/TraceTree"
import {nodeTypeStyles} from "./components/AvatarTreeContent"
import StatusRenderer from "./components/StatusRenderer"
import TraceContent from "./drawer/TraceContent"
import TraceHeader from "./drawer/TraceHeader"
import TraceTree from "./drawer/TraceTree"
import Filters from "@/components/Filters/Filters"
import Sort, {SortResult} from "@/components/Filters/Sort"
import EditColumns from "@/components/Filters/EditColumns"
Expand Down Expand Up @@ -56,9 +56,7 @@ const useStyles = createUseStyles((theme: JSSTheme) => ({
},
}))

interface Props {}

const ObservabilityDashboard = ({}: Props) => {
const ObservabilityDashboard = () => {
const {
traces,
isLoading,
Expand Down Expand Up @@ -445,8 +443,8 @@ const ObservabilityDashboard = ({}: Props) => {
setFilters(newFilters)
}, [])

const onClearFilter = useCallback(() => {
setFilters([])
const onClearFilter = useCallback((filter: Filter[]) => {
setFilters(filter)
setSearchQuery("")
if (traceTabs === "chat") {
setTraceTabs("tree")
Expand Down Expand Up @@ -569,8 +567,11 @@ const ObservabilityDashboard = ({}: Props) => {
}
description="Monitor the performance and results of your LLM applications here."
primaryCta={{
text: "Go to Playground",
onClick: () => router.push(`/apps/${appId}/playground`),
text: appId ? "Go to Playground" : "Create an Application",
onClick: () =>
router.push(
appId ? `/apps/${appId}/playground` : "/apps",
),
tooltip:
"Run your LLM app in the playground to generate and view insights.",
}}
Expand Down
20 changes: 9 additions & 11 deletions agenta-web/src/contexts/observability.context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,11 @@ const ObservabilityContextProvider: React.FC<PropsWithChildren> = ({children}) =
// query states
const [searchQuery, setSearchQuery] = useState("")
const [traceTabs, setTraceTabs] = useState<TraceTabTypes>("tree")
const [filters, setFilters] = useState<Filter[]>([])
const [filters, setFilters] = useState<Filter[]>(
appId
? [{key: "refs.application.id", operator: "is", value: appId, isPermanent: true}]
: [],
)
const [sort, setSort] = useState<SortResult>({} as SortResult)
const [pagination, setPagination] = useState({page: 1, size: 10})

Expand Down Expand Up @@ -119,14 +123,10 @@ const ObservabilityContextProvider: React.FC<PropsWithChildren> = ({children}) =
focus: traceTabs === "chat" ? "node" : traceTabs,
}

if (appId) {
params.filtering = JSON.stringify({
conditions: [{key: "refs.application.id", operator: "is", value: appId}],
})
}

if (filters.length > 0) {
params.filtering = JSON.stringify({conditions: filters})
const sanitizedFilters = filters.map(({isPermanent, ...rest}) => rest)

params.filtering = JSON.stringify({conditions: sanitizedFilters})
}

if (sort) {
Expand All @@ -150,9 +150,7 @@ const ObservabilityContextProvider: React.FC<PropsWithChildren> = ({children}) =
}

useEffect(() => {
if (appId) {
fetchTraces()
}
fetchTraces()
}, [appId, filters, traceTabs, sort, pagination])

observabilityContextValues.traces = traces
Expand Down
1 change: 1 addition & 0 deletions agenta-web/src/lib/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,7 @@ export type Filter = {
key: string
operator: FilterConditions
value: string
isPermanent?: boolean
}

export type FilterConditions =
Expand Down
7 changes: 7 additions & 0 deletions agenta-web/src/pages/apps/[app_id]/traces/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import ObservabilityDashboard from "@/components/pages/observability/ObservabilityDashboard"

const Traces = () => {
return <ObservabilityDashboard />
}

export default Traces
12 changes: 12 additions & 0 deletions agenta-web/src/pages/observability/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import ProtectedRoute from "@/components/ProtectedRoute/ProtectedRoute"
import ObservabilityDashboard from "@/components/pages/observability/ObservabilityDashboard"

const GlobalObservability = () => {
return <ObservabilityDashboard />
}

export default () => (
<ProtectedRoute>
<GlobalObservability />
</ProtectedRoute>
)