Skip to content

Commit ed68c02

Browse files
authored
feat(code): Signals inbox progressive, prioritized, professional (#1305)
## Problem PostHog Code users who onboard to self-driving need a clear experience of reports flowing in: see what's processing vs. ready, see readable summaries without opening the web app, and triage by actionability priority (P0–P4) for researched reports. ## Changes _Depends on PostHog/posthog#51740._ Adding the above, with progressive loading, polling, and and onboarding/warming states for connected sources. (as summarized by Claude:) - **Inbox**: progressive loading, window-focus–gated refetch, combined pipeline status filter, sort/helpers (`inboxConstants`, `inboxSort`) - **Sidebar**: ready count and indicator when pipeline work is in flight - **Reports**: markdown summaries in list and detail; **priority** chips aligned with the status chip height (consumes optional `priority` from the API) - **UI**: warming/empty states, live rail, `rendererWindowFocusStore` for focus-aware polling - **Types**: optional `priority` on `SignalReport`; related client/query hook updates ## How did you test this code? https://github.com/user-attachments/assets/bc278e19-6a2d-403a-985d-0c0d85e4ba7c ## Publish to changelog? do not publish to changelog ## Docs update N/A
1 parent 4428136 commit ed68c02

24 files changed

Lines changed: 813 additions & 114 deletions

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ export interface ExternalDataSourceSchema {
3737
id: string;
3838
name: string;
3939
should_sync: boolean;
40+
/** e.g. `full_refresh` (full table replication), `incremental`, `append` */
41+
sync_type?: string | null;
4042
}
4143

4244
export interface ExternalDataSource {
@@ -327,7 +329,7 @@ export class PostHogAPIClient {
327329
async updateExternalDataSchema(
328330
projectId: number,
329331
schemaId: string,
330-
updates: { should_sync: boolean },
332+
updates: { should_sync: boolean; sync_type?: string },
331333
): Promise<void> {
332334
const urlPath = `/api/projects/${projectId}/external_data_schemas/${schemaId}/`;
333335
const url = new URL(`${this.api.baseUrl}${urlPath}`);

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

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,14 @@ const REQUIRED_SCHEMAS: Record<DataSourceType, string[]> = {
1414
zendesk: ["tickets"],
1515
};
1616

17+
/** PostHog DWH: full table replication (non-incremental); API enum value `full_refresh`. */
18+
const FULL_TABLE_REPLICATION = "full_refresh" as const;
19+
1720
function schemasPayload(source: DataSourceType) {
1821
return REQUIRED_SCHEMAS[source].map((name) => ({
1922
name,
2023
should_sync: true,
21-
sync_type: "full_refresh" as const,
24+
sync_type: FULL_TABLE_REPLICATION,
2225
}));
2326
}
2427

@@ -64,13 +67,20 @@ function GitHubSetup({ onComplete, onCancel }: SetupFormProps) {
6467
}, [repo, repositories]);
6568

6669
const handleSubmit = useCallback(async () => {
67-
if (!projectId || !client || !repo) return;
70+
if (!projectId || !client || !repo || !githubIntegration) return;
6871

6972
setLoading(true);
7073
try {
7174
await client.createExternalDataSource(projectId, {
7275
source_type: "Github",
73-
payload: { repository: repo, schemas: schemasPayload("github") },
76+
payload: {
77+
repository: repo,
78+
auth_method: {
79+
selection: "oauth",
80+
github_integration_id: githubIntegration.id,
81+
},
82+
schemas: schemasPayload("github"),
83+
},
7484
});
7585
toast.success("GitHub data source created");
7686
onComplete();
@@ -81,11 +91,11 @@ function GitHubSetup({ onComplete, onCancel }: SetupFormProps) {
8191
} finally {
8292
setLoading(false);
8393
}
84-
}, [projectId, client, repo, onComplete]);
94+
}, [projectId, client, repo, githubIntegration, onComplete]);
8595

8696
if (!githubIntegration) {
8797
return (
88-
<SetupFormContainer title="Connect GitHub" onCancel={onCancel}>
98+
<SetupFormContainer title="Connect GitHub">
8999
<Text size="2" style={{ color: "var(--gray-11)" }}>
90100
No GitHub integration found. Please connect GitHub during onboarding
91101
first.
@@ -95,7 +105,7 @@ function GitHubSetup({ onComplete, onCancel }: SetupFormProps) {
95105
}
96106

97107
return (
98-
<SetupFormContainer title="Connect GitHub" onCancel={onCancel}>
108+
<SetupFormContainer title="Connect GitHub">
99109
<Flex direction="column" gap="3">
100110
<GitHubRepoPicker
101111
value={repo}
@@ -122,7 +132,7 @@ function GitHubSetup({ onComplete, onCancel }: SetupFormProps) {
122132
const POLL_INTERVAL_MS = 3_000;
123133
const POLL_TIMEOUT_MS = 300_000; // 5 minutes
124134

125-
function LinearSetup({ onComplete, onCancel }: SetupFormProps) {
135+
function LinearSetup({ onComplete }: SetupFormProps) {
126136
const cloudRegion = useAuthStore((s) => s.cloudRegion);
127137
const projectId = useAuthStore((s) => s.projectId);
128138
const client = useAuthStore((s) => s.client);
@@ -210,7 +220,7 @@ function LinearSetup({ onComplete, onCancel }: SetupFormProps) {
210220
}, [projectId, client, onComplete]);
211221

212222
return (
213-
<SetupFormContainer title="Connect Linear" onCancel={onCancel}>
223+
<SetupFormContainer title="Connect Linear">
214224
<Flex direction="column" gap="3">
215225
<Button
216226
size="2"
@@ -222,7 +232,7 @@ function LinearSetup({ onComplete, onCancel }: SetupFormProps) {
222232
? "Linear connected"
223233
: loading
224234
? "Waiting for authorization..."
225-
: "Connect Linear"}
235+
: "Log into Linear to continue"}
226236
</Button>
227237

228238
{pollError && (
@@ -285,7 +295,7 @@ function ZendeskSetup({ onComplete, onCancel }: SetupFormProps) {
285295
const canSubmit = subdomain.trim() && apiKey.trim() && email.trim();
286296

287297
return (
288-
<SetupFormContainer title="Connect Zendesk" onCancel={onCancel}>
298+
<SetupFormContainer title="Connect Zendesk">
289299
<Flex direction="column" gap="3">
290300
<TextField.Root
291301
placeholder="Subdomain (e.g. mycompany)"
@@ -324,11 +334,9 @@ function ZendeskSetup({ onComplete, onCancel }: SetupFormProps) {
324334

325335
function SetupFormContainer({
326336
title,
327-
onCancel,
328337
children,
329338
}: {
330339
title: string;
331-
onCancel: () => void;
332340
children: React.ReactNode;
333341
}) {
334342
return (
@@ -344,9 +352,6 @@ function SetupFormContainer({
344352
<Text size="2" weight="medium" style={{ color: "var(--gray-12)" }}>
345353
{title}
346354
</Text>
347-
<Button size="1" variant="ghost" onClick={onCancel}>
348-
Cancel
349-
</Button>
350355
</Flex>
351356
{children}
352357
</Flex>
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
interface InboxLiveRailProps {
2+
active: boolean;
3+
}
4+
5+
/**
6+
* Thin “instrument” scan line while live polling is active — industrial / lab aesthetic.
7+
*/
8+
export function InboxLiveRail({ active }: InboxLiveRailProps) {
9+
if (!active) {
10+
return null;
11+
}
12+
13+
return (
14+
<div
15+
className="relative mb-0 h-px w-full overflow-hidden"
16+
style={{ background: "var(--gray-5)" }}
17+
aria-hidden
18+
>
19+
<div
20+
className="absolute inset-y-0 w-[28%] opacity-95"
21+
style={{
22+
background:
23+
"linear-gradient(90deg, transparent, var(--amber-9), var(--orange-9), transparent)",
24+
animation:
25+
"inboxLiveRailSweep 2.1s cubic-bezier(0.45, 0, 0.55, 1) infinite",
26+
}}
27+
/>
28+
</div>
29+
);
30+
}

0 commit comments

Comments
 (0)