mirror of
https://github.com/hanzoai/insights.git
synced 2026-11-02 09:24:48 +00:00
Every first-party Python caller and test now names the mount the API actually answers on. Mechanical: URL literals only, and only where the /api/ was ours -- a preceding word character means it was a module path like insights/api/ or a third-party host like slack.com/api/, and those are untouched. Left saying /api/, each for a reason rather than for safety: - products/warehouse_sources/.../sources/** is a catalogue of vendor endpoints - services/llm-gateway deploys separately and is under a code freeze, so moving its two calls would break it during the skew - the mcp_store and Slack/Teams redirect_uris are registered with third parties and must byte-match what was registered - the Wizard and Raycast client-metadata paths are OAuth client_ids - /api/surveys and /api/feature_flag/local_evaluation are SDK aliases the ingress routes to the Rust fleets, held by released SDK versions Test URLconfs moved with the requests that call them, and the Datastore user-selection fixtures now carry the leading slash that request.path has.
160 lines
5.0 KiB
TypeScript
160 lines
5.0 KiB
TypeScript
import { MakeLogicType, actions, connect, kea, listeners, path, reducers } from 'kea'
|
|
import { loaders } from 'kea-loaders'
|
|
|
|
import { toast } from '@hanzo/elements'
|
|
|
|
import api from 'lib/api'
|
|
import { teamLogic } from 'scenes/teamLogic'
|
|
|
|
import { TRACING_SCENE_VIEWER_ID, TracingFilters, tracingFiltersLogic } from '../tracingFiltersLogic'
|
|
|
|
// Subset of TracingFilters persisted in a saved view. Compare-mode and the dragged overlay windows
|
|
// are ephemeral UI state tied to on-screen sparkline data, so they're intentionally excluded.
|
|
export type SavedTracingFilters = Pick<
|
|
TracingFilters,
|
|
'dateRange' | 'serviceNames' | 'filterGroup' | 'orderBy' | 'orderDirection' | 'viewMode'
|
|
>
|
|
|
|
// Handwritten until `insightscli build:openapi` generates `TracingViewApi` from TracingViewSerializer.
|
|
export interface TracingView {
|
|
id: string
|
|
short_id: string
|
|
name: string
|
|
filters: Partial<SavedTracingFilters>
|
|
pinned: boolean
|
|
created_at: string
|
|
created_by: {
|
|
first_name?: string
|
|
email?: string
|
|
} | null
|
|
updated_at: string | null
|
|
}
|
|
|
|
const tracingViewsUrl = (teamId: number | null): string => `v1/projects/${teamId}/tracing/views`
|
|
|
|
// Generated by kea-typegen. Update if you're an agent, ignore if you're human.
|
|
export interface tracingViewsLogicValues {
|
|
currentTeamId: number | null // teamLogic
|
|
views: TracingView[]
|
|
viewsLoading: boolean
|
|
}
|
|
|
|
// Generated by kea-typegen. Update if you're an agent, ignore if you're human.
|
|
export interface tracingViewsLogicActions {
|
|
setFilters: (filters: Partial<TracingFilters>) => {
|
|
filters: Partial<TracingFilters>
|
|
} // tracingFiltersLogic
|
|
createView: ({ name, filters }: { filters: Partial<SavedTracingFilters>; name: string }) => {
|
|
name: string
|
|
filters: Partial<SavedTracingFilters>
|
|
}
|
|
createViewFailure: (
|
|
error: string,
|
|
errorObject?: any
|
|
) => {
|
|
error: string
|
|
errorObject?: any
|
|
}
|
|
createViewSuccess: (
|
|
views: TracingView[],
|
|
payload?: {
|
|
name: string
|
|
filters: Partial<SavedTracingFilters>
|
|
}
|
|
) => {
|
|
views: TracingView[]
|
|
payload?: {
|
|
name: string
|
|
filters: Partial<SavedTracingFilters>
|
|
}
|
|
}
|
|
deleteView: (shortId: string) => {
|
|
shortId: string
|
|
}
|
|
loadView: (view: TracingView) => {
|
|
view: TracingView
|
|
}
|
|
loadViews: () => any
|
|
loadViewsFailure: (
|
|
error: string,
|
|
errorObject?: any
|
|
) => {
|
|
error: string
|
|
errorObject?: any
|
|
}
|
|
loadViewsSuccess: (
|
|
views: TracingView[],
|
|
payload?: any
|
|
) => {
|
|
views: TracingView[]
|
|
payload?: any
|
|
}
|
|
}
|
|
|
|
export type tracingViewsLogicType = MakeLogicType<tracingViewsLogicValues, tracingViewsLogicActions>
|
|
|
|
export const tracingViewsLogic = kea<tracingViewsLogicType>([
|
|
path(['products', 'tracing', 'frontend', 'savedViews', 'tracingViewsLogic']),
|
|
|
|
// Saved views are a /tracing scene feature — always bind the scene's viewer instance.
|
|
connect(() => ({
|
|
values: [teamLogic, ['currentTeamId']],
|
|
actions: [tracingFiltersLogic({ id: TRACING_SCENE_VIEWER_ID }), ['setFilters']],
|
|
})),
|
|
|
|
actions({
|
|
deleteView: (shortId: string) => ({ shortId }),
|
|
loadView: (view: TracingView) => ({ view }),
|
|
}),
|
|
|
|
loaders(({ values }) => ({
|
|
views: [
|
|
[] as TracingView[],
|
|
{
|
|
loadViews: async () => {
|
|
// nosemgrep: prefer-codegen-api
|
|
const response = await api.get(`${tracingViewsUrl(values.currentTeamId)}/`)
|
|
return response.results
|
|
},
|
|
createView: async ({ name, filters }: { name: string; filters: Partial<SavedTracingFilters> }) => {
|
|
// nosemgrep: prefer-codegen-api
|
|
const created: TracingView = await api.create(`${tracingViewsUrl(values.currentTeamId)}/`, {
|
|
name,
|
|
filters,
|
|
})
|
|
toast.success('View saved')
|
|
return [created, ...values.views]
|
|
},
|
|
},
|
|
],
|
|
})),
|
|
|
|
reducers({
|
|
views: {
|
|
deleteView: (state, { shortId }) => state.filter((v) => v.short_id !== shortId),
|
|
},
|
|
}),
|
|
|
|
listeners(({ actions, values }) => ({
|
|
deleteView: async ({ shortId }) => {
|
|
try {
|
|
// nosemgrep: prefer-codegen-api
|
|
await api.delete(`${tracingViewsUrl(values.currentTeamId)}/${shortId}/`)
|
|
toast.success('View deleted')
|
|
} catch {
|
|
toast.error('Failed to delete view')
|
|
actions.loadViews()
|
|
}
|
|
},
|
|
loadView: ({ view }) => {
|
|
actions.setFilters(view.filters || {})
|
|
},
|
|
createViewFailure: () => {
|
|
toast.error('Failed to save view')
|
|
},
|
|
loadViewsFailure: () => {
|
|
toast.error('Failed to load saved views')
|
|
},
|
|
})),
|
|
])
|