Skip to content

Commit c736764

Browse files
committed
feat(inbox): error tracking source, LLM evaluations, source config improvements
- Add error tracking as signal source with 3 sub-types toggled together - Replace non-functional LLM analytics toggle with evaluations list (polls 5s) - Evaluations link to Cloud for management (region-aware) - Fix re-render cascade: direct API calls, per-source optimistic state - Per-source onToggle API with memoized cards - Rounded toggle cards, GitHub OAuth flow - Add suggested reviewer + artefact types
1 parent 46131fa commit c736764

File tree

10 files changed

+638
-230
lines changed

10 files changed

+638
-230
lines changed

apps/code/src/renderer/api/posthogClient.ts

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,25 @@ export type McpRecommendedServer = Schemas.RecommendedServer;
2020

2121
export type McpServerInstallation = Schemas.MCPServerInstallation;
2222

23+
export type Evaluation = Schemas.Evaluation;
24+
2325
export interface SignalSourceConfig {
2426
id: string;
2527
source_product:
2628
| "session_replay"
2729
| "llm_analytics"
2830
| "github"
2931
| "linear"
30-
| "zendesk";
31-
source_type: "session_analysis_cluster" | "evaluation" | "issue" | "ticket";
32+
| "zendesk"
33+
| "error_tracking";
34+
source_type:
35+
| "session_analysis_cluster"
36+
| "evaluation"
37+
| "issue"
38+
| "ticket"
39+
| "issue_created"
40+
| "issue_reopened"
41+
| "issue_spiking";
3242
enabled: boolean;
3343
config: Record<string, unknown>;
3444
created_at: string;
@@ -223,17 +233,8 @@ export class PostHogAPIClient {
223233
async createSignalSourceConfig(
224234
projectId: number,
225235
options: {
226-
source_product:
227-
| "session_replay"
228-
| "llm_analytics"
229-
| "github"
230-
| "linear"
231-
| "zendesk";
232-
source_type:
233-
| "session_analysis_cluster"
234-
| "evaluation"
235-
| "issue"
236-
| "ticket";
236+
source_product: SignalSourceConfig["source_product"];
237+
source_type: SignalSourceConfig["source_type"];
237238
enabled: boolean;
238239
config?: Record<string, unknown>;
239240
},
@@ -287,6 +288,34 @@ export class PostHogAPIClient {
287288
return (await response.json()) as SignalSourceConfig;
288289
}
289290

291+
async listEvaluations(projectId: number): Promise<Evaluation[]> {
292+
const data = await this.api.get(
293+
"/api/environments/{project_id}/evaluations/",
294+
{
295+
path: { project_id: projectId.toString() },
296+
query: { limit: 200 },
297+
},
298+
);
299+
return data.results ?? [];
300+
}
301+
302+
async updateEvaluation(
303+
projectId: number,
304+
evaluationId: string,
305+
updates: { enabled: boolean },
306+
): Promise<Evaluation> {
307+
return await this.api.patch(
308+
"/api/environments/{project_id}/evaluations/{id}/",
309+
{
310+
path: {
311+
project_id: projectId.toString(),
312+
id: evaluationId,
313+
},
314+
body: updates,
315+
},
316+
);
317+
}
318+
290319
async listExternalDataSources(
291320
projectId: number,
292321
): Promise<ExternalDataSource[]> {

apps/code/src/renderer/features/inbox/components/DataSourceSetup.tsx

Lines changed: 91 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,41 @@ interface SetupFormProps {
5151
onCancel: () => void;
5252
}
5353

54+
const POLL_INTERVAL_GITHUB_MS = 3_000;
55+
const POLL_TIMEOUT_GITHUB_MS = 300_000;
56+
5457
function GitHubSetup({ onComplete, onCancel }: SetupFormProps) {
5558
const projectId = useAuthStore((s) => s.projectId);
59+
const cloudRegion = useAuthStore((s) => s.cloudRegion);
5660
const client = useAuthStore((s) => s.client);
5761
const { githubIntegration, repositories, isLoadingRepos } =
5862
useRepositoryIntegration();
5963
const [repo, setRepo] = useState<string | null>(null);
6064
const [loading, setLoading] = useState(false);
65+
const [connecting, setConnecting] = useState(false);
66+
const pollTimerRef = useRef<ReturnType<typeof setInterval> | null>(null);
67+
const pollTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
68+
69+
const stopPolling = useCallback(() => {
70+
if (pollTimerRef.current) {
71+
clearInterval(pollTimerRef.current);
72+
pollTimerRef.current = null;
73+
}
74+
if (pollTimeoutRef.current) {
75+
clearTimeout(pollTimeoutRef.current);
76+
pollTimeoutRef.current = null;
77+
}
78+
}, []);
79+
80+
useEffect(() => stopPolling, [stopPolling]);
81+
82+
// Stop polling once integration appears
83+
useEffect(() => {
84+
if (githubIntegration && connecting) {
85+
stopPolling();
86+
setConnecting(false);
87+
}
88+
}, [githubIntegration, connecting, stopPolling]);
6189

6290
// Auto-select the first repo once loaded
6391
useEffect(() => {
@@ -66,6 +94,47 @@ function GitHubSetup({ onComplete, onCancel }: SetupFormProps) {
6694
}
6795
}, [repo, repositories]);
6896

97+
const handleConnectGitHub = useCallback(async () => {
98+
if (!cloudRegion || !projectId) return;
99+
setConnecting(true);
100+
try {
101+
await trpcClient.githubIntegration.startFlow.mutate({
102+
region: cloudRegion,
103+
projectId,
104+
});
105+
106+
pollTimerRef.current = setInterval(async () => {
107+
try {
108+
if (!client) return;
109+
// Trigger a refetch of integrations
110+
const integrations =
111+
await client.getIntegrationsForProject(projectId);
112+
const hasGithub = integrations.some(
113+
(i: { kind: string }) => i.kind === "github",
114+
);
115+
if (hasGithub) {
116+
stopPolling();
117+
setConnecting(false);
118+
toast.success("GitHub connected");
119+
}
120+
} catch {
121+
// Ignore individual poll failures
122+
}
123+
}, POLL_INTERVAL_GITHUB_MS);
124+
125+
pollTimeoutRef.current = setTimeout(() => {
126+
stopPolling();
127+
setConnecting(false);
128+
toast.error("Connection timed out. Please try again.");
129+
}, POLL_TIMEOUT_GITHUB_MS);
130+
} catch (error) {
131+
setConnecting(false);
132+
toast.error(
133+
error instanceof Error ? error.message : "Failed to start GitHub flow",
134+
);
135+
}
136+
}, [cloudRegion, projectId, client, stopPolling]);
137+
69138
const handleSubmit = useCallback(async () => {
70139
if (!projectId || !client || !repo || !githubIntegration) return;
71140

@@ -96,10 +165,28 @@ function GitHubSetup({ onComplete, onCancel }: SetupFormProps) {
96165
if (!githubIntegration) {
97166
return (
98167
<SetupFormContainer title="Connect GitHub">
99-
<Text size="2" style={{ color: "var(--gray-11)" }}>
100-
No GitHub integration found. Please connect GitHub during onboarding
101-
first.
102-
</Text>
168+
<Flex direction="column" gap="3">
169+
<Text size="2" style={{ color: "var(--gray-11)" }}>
170+
Connect your GitHub account to import issues as signals.
171+
</Text>
172+
<Flex gap="2" justify="end">
173+
<Button
174+
size="2"
175+
variant="soft"
176+
onClick={onCancel}
177+
disabled={connecting}
178+
>
179+
Cancel
180+
</Button>
181+
<Button
182+
size="2"
183+
onClick={() => void handleConnectGitHub()}
184+
disabled={connecting}
185+
>
186+
{connecting ? "Waiting for authorization..." : "Connect GitHub"}
187+
</Button>
188+
</Flex>
189+
</Flex>
103190
</SetupFormContainer>
104191
);
105192
}

0 commit comments

Comments
 (0)