diff --git a/apps/code/src/renderer/features/inbox/components/DataSourceSetup.tsx b/apps/code/src/renderer/features/inbox/components/DataSourceSetup.tsx index 406781f68..3f7dfeb9e 100644 --- a/apps/code/src/renderer/features/inbox/components/DataSourceSetup.tsx +++ b/apps/code/src/renderer/features/inbox/components/DataSourceSetup.tsx @@ -9,7 +9,8 @@ import { useGithubRepositories, useRepositoryIntegration, } from "@hooks/useIntegrations"; -import { Box, Button, Flex, Text, TextField } from "@radix-ui/themes"; +import { Button } from "@posthog/quill"; +import { Box, Flex, Text, TextField } from "@radix-ui/themes"; import { trpcClient } from "@renderer/trpc"; import { useCallback, useEffect, useRef, useState } from "react"; import { toast } from "sonner"; @@ -185,11 +186,18 @@ function GitHubSetup({ onComplete, onCancel }: SetupFormProps) { {statusMessage} - - - - ); -} - export function WarmingUpPane({ onConfigureSources, enabledProducts, diff --git a/apps/code/src/renderer/features/inbox/components/InboxSetupPane.tsx b/apps/code/src/renderer/features/inbox/components/InboxSetupPane.tsx new file mode 100644 index 000000000..aee373636 --- /dev/null +++ b/apps/code/src/renderer/features/inbox/components/InboxSetupPane.tsx @@ -0,0 +1,66 @@ +import { SignalSourcesSettings } from "@features/settings/components/sections/SignalSourcesSettings"; +import { ArrowRightIcon } from "@phosphor-icons/react"; +import { Button } from "@posthog/quill"; +import { Flex, Text, Tooltip } from "@radix-ui/themes"; +import { motion } from "framer-motion"; + +interface InboxSetupPaneProps { + hasSignalSources: boolean; + onProceedToInbox: () => void; +} + +export function InboxSetupPane({ + hasSignalSources, + onProceedToInbox, +}: InboxSetupPaneProps) { + return ( + + + + + Set up self-driving for your product + + + + + + + + + {hasSignalSources ? ( + + ) : ( + + + + + + )} + + + + ); +} diff --git a/apps/code/src/renderer/features/inbox/components/InboxSignalsTab.tsx b/apps/code/src/renderer/features/inbox/components/InboxSignalsTab.tsx index 480377488..57f2e8094 100644 --- a/apps/code/src/renderer/features/inbox/components/InboxSignalsTab.tsx +++ b/apps/code/src/renderer/features/inbox/components/InboxSignalsTab.tsx @@ -4,8 +4,8 @@ import { SelectReportPane, SkeletonBackdrop, WarmingUpPane, - WelcomePane, } from "@features/inbox/components/InboxEmptyStates"; +import { InboxSetupPane } from "@features/inbox/components/InboxSetupPane"; import { InboxSourcesDialog } from "@features/inbox/components/InboxSourcesDialog"; import { inboxBulkSnoozeDisabledReason, @@ -475,11 +475,25 @@ export function InboxSignalsTab() { sourceProductFilter.length > 0 || suggestedReviewerFilter.length > 0 || statusFilter.length < 5; + // Onboarding wins over two-pane even if the user has suggested setup tasks — + // discovered tasks alone shouldn't push a source-less user past the inline setup. + const onboardingShouldShow = !hasReports && !hasSignalSources; + // Sticky within an inbox visit: once we've entered onboarding, keep showing + // it even after the user toggles a source on, until either they explicitly + // click "Proceed to Inbox" or navigate away (unmount resets the ref). + const enteredOnboardingRef = useRef(false); + if (onboardingShouldShow) { + enteredOnboardingRef.current = true; + } + const [userExitedOnboarding, setUserExitedOnboarding] = useState(false); + const showInboxOnboarding = + enteredOnboardingRef.current && !userExitedOnboarding; const shouldShowTwoPane = - hasReports || - !!searchQuery.trim() || - hasActiveFilters || - hasDiscoveredTasks; + !showInboxOnboarding && + (hasReports || + !!searchQuery.trim() || + hasActiveFilters || + hasDiscoveredTasks); // Sticky: once we enter two-pane mode, stay there even if a refetch // momentarily empties the list (e.g. when sort order changes). @@ -686,7 +700,19 @@ export function InboxSignalsTab() { return ( <> - {showTwoPaneLayout ? ( + {showInboxOnboarding ? ( + // Inline setup pane for users with no sources configured. + // The toolbar (report counter, search, bulk actions) is suppressed + // entirely — none of it is meaningful before any source is configured. + // Sticky within the visit: stays until the user clicks "Proceed to + // Inbox" inside the pane or navigates away. + + setUserExitedOnboarding(true)} + /> + + ) : showTwoPaneLayout ? ( {/* ── Left pane: report list ───────────────────────────────── */} ) : ( - /* ── Full-width empty state with skeleton backdrop ──────── */ + // Full-width warming-up state with skeleton backdrop - {!hasSignalSources || !hasGithubIntegration ? ( - setSourcesDialogOpen(true)} /> - ) : ( - setSourcesDialogOpen(true)} - enabledProducts={enabledProducts} - /> - )} + setSourcesDialogOpen(true)} + enabledProducts={enabledProducts} + /> diff --git a/apps/code/src/renderer/features/inbox/components/SignalSourceToggles.tsx b/apps/code/src/renderer/features/inbox/components/SignalSourceToggles.tsx index f727f2308..f295ed602 100644 --- a/apps/code/src/renderer/features/inbox/components/SignalSourceToggles.tsx +++ b/apps/code/src/renderer/features/inbox/components/SignalSourceToggles.tsx @@ -11,15 +11,8 @@ import { TicketIcon, VideoIcon, } from "@phosphor-icons/react"; -import { - Box, - Button, - Flex, - Spinner, - Switch, - Text, - Tooltip, -} from "@radix-ui/themes"; +import { Button } from "@posthog/quill"; +import { Box, Flex, Spinner, Switch, Text, Tooltip } from "@radix-ui/themes"; import type { SignalSourceConfig } from "@renderer/api/posthogClient"; import { memo, useCallback } from "react"; @@ -140,7 +133,9 @@ const SignalSourceToggleCard = memo(function SignalSourceToggleCard({ ) : requiresSetup ? ( - ) : ( - )} ); diff --git a/apps/code/src/renderer/features/settings/components/sections/SignalSlackNotificationsSettings.tsx b/apps/code/src/renderer/features/settings/components/sections/SignalSlackNotificationsSettings.tsx index 99d66e784..7b0c6f297 100644 --- a/apps/code/src/renderer/features/settings/components/sections/SignalSlackNotificationsSettings.tsx +++ b/apps/code/src/renderer/features/settings/components/sections/SignalSlackNotificationsSettings.tsx @@ -7,6 +7,7 @@ import { SettingsOptionSelect } from "@features/settings/components/SettingsOpti import { useDebouncedValue } from "@hooks/useDebouncedValue"; import { CaretDown, Hash, Lock } from "@phosphor-icons/react"; import { + Button, Combobox, ComboboxContent, ComboboxEmpty, @@ -14,9 +15,8 @@ import { ComboboxItem, ComboboxList, ComboboxTrigger, - Button as QuillButton, } from "@posthog/quill"; -import { Button, Callout, Flex, Text } from "@radix-ui/themes"; +import { Callout, Flex, Text } from "@radix-ui/themes"; import type { SignalReportPriority, SlackChannelOption } from "@shared/types"; import { useMemo, useRef, useState } from "react"; @@ -175,12 +175,14 @@ export function SignalSlackNotificationsSettings({ } /> {channelComboboxModal ? ( diff --git a/apps/code/src/renderer/features/settings/components/sections/SignalSourcesSettings.tsx b/apps/code/src/renderer/features/settings/components/sections/SignalSourcesSettings.tsx index 77b3e4614..b5034eab8 100644 --- a/apps/code/src/renderer/features/settings/components/sections/SignalSourcesSettings.tsx +++ b/apps/code/src/renderer/features/settings/components/sections/SignalSourcesSettings.tsx @@ -19,7 +19,7 @@ const PRIORITY_OPTIONS: { value: SignalReportPriority; label: string }[] = [ const NEVER_VALUE = "__never__"; const USER_PRIORITY_OPTIONS: { value: string; label: string }[] = [ - { value: NEVER_VALUE, label: "Never — opt out of auto-assigned tasks" }, + { value: NEVER_VALUE, label: "Never – opt out of auto-assigned tasks" }, ...PRIORITY_OPTIONS, ]; @@ -59,9 +59,10 @@ export function SignalSourcesSettings({ return ( - - Automatically analyze your product data and surface actionable insights. - Choose which sources to enable for this project. + + Connect GitHub and pick which sources to monitor. PostHog Code will + analyze activity around the clock and surface ready-to-merge fixes and + improvements.