Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export function WarmingUpPane({
color="gray"
onClick={onConfigureSources}
>
Configure sources
Configure inbox
</Button>
</Flex>
</Flex>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -416,3 +416,52 @@ export function SignalSourceToggles({
</Flex>
);
}

function SignalSourceToggleCardSkeleton() {
return (
<Box
p="3"
className="rounded-(--radius-3) border border-(--gray-4) bg-(--color-panel-solid)"
>
<Flex align="center" justify="between" gap="4">
<Flex align="center" gap="3" className="min-w-0 flex-1">
<Box className="size-[20px] shrink-0 animate-pulse rounded bg-gray-4" />
<Flex direction="column" gap="2" className="min-w-0 flex-1">
<Box className="h-[12px] w-[50%] animate-pulse rounded bg-gray-4" />
<Box className="h-[11px] w-[80%] animate-pulse rounded bg-gray-3" />
</Flex>
</Flex>
<Box className="h-[18px] w-[32px] shrink-0 animate-pulse rounded-full bg-gray-3" />
</Flex>
</Box>
);
}

export function SignalSourceTogglesSkeleton() {
return (
<Flex gap="4">
<Flex direction="column" gap="2" className="min-w-0 flex-1">
<Text className="font-medium text-(--gray-9) text-[13px]">
PostHog data
</Text>
<Flex direction="column" gap="3">
{Array.from({ length: 3 }).map((_, index) => (
// biome-ignore lint/suspicious/noArrayIndexKey: static loading placeholders
<SignalSourceToggleCardSkeleton key={index} />
))}
</Flex>
</Flex>
<Flex direction="column" gap="2" className="min-w-0 flex-1">
<Text className="font-medium text-(--gray-9) text-[13px]">
External connections
</Text>
<Flex direction="column" gap="3">
{Array.from({ length: 4 }).map((_, index) => (
// biome-ignore lint/suspicious/noArrayIndexKey: static loading placeholders
<SignalSourceToggleCardSkeleton key={index} />
))}
</Flex>
</Flex>
</Flex>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ interface SignalsToolbarProps {
effectiveBulkIds?: string[];
/** Called when the select-all checkbox is toggled. Parent owns all state transitions. */
onToggleSelectAll?: (checked: boolean) => void;
/** Called when the "Configure sources" button is clicked. */
/** Called when the "Configure inbox" button is clicked. */
onConfigureSources?: () => void;
/**
* Opens the dismiss flow: exactly one report selected (snooze or permanent suppress, with a reason).
Expand Down Expand Up @@ -505,7 +505,7 @@ export function SignalsToolbar({
className="flex shrink-0 cursor-pointer items-center gap-1 border-0 bg-transparent p-0 text-[12px] text-gray-10 transition-colors hover:text-gray-12"
>
<GearSixIcon size={12} />
<span>Configure sources</span>
<span>Configure inbox</span>
</button>
) : null}
</Flex>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ export function useSignalSourceManager() {
useExternalDataSources();
const { data: evaluations } = useEvaluations();
const { data: teamConfig } = useSignalTeamConfig();
const { data: userAutonomyConfig } = useSignalUserAutonomyConfig();
const { data: userAutonomyConfig, isLoading: userAutonomyConfigLoading } =
useSignalUserAutonomyConfig();

// Optimistic overrides keyed by source product — only sources actively being
// toggled get an entry, so unrelated sources never see a prop change.
Expand Down Expand Up @@ -573,6 +574,7 @@ export function useSignalSourceManager() {
teamConfig,
handleUpdateAutostartPriority,
userAutonomyConfig,
userAutonomyConfigLoading,
handleUpdateUserAutonomyPriority,
handleUpdateSlackNotifications,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@ function summarizeReposByOwner(

export function GitHubIntegrationSection({
hasGithubIntegration,
isLoading = false,
}: {
hasGithubIntegration: boolean;
isLoading?: boolean;
}) {
const { repositories, isLoadingRepos } = useRepositoryIntegration();
const ownerSummary = useMemo(
Expand All @@ -58,6 +60,27 @@ export function GitHubIntegrationSection({
projectHasTeamIntegration: hasGithubIntegration,
});

if (isLoading) {
return (
<Flex
align="center"
justify="between"
gap="4"
pb="4"
className="border-(--gray-5) border-b border-dashed"
>
<Flex align="center" gap="3" className="min-w-0 flex-1">
<Box className="size-[20px] shrink-0 animate-pulse rounded bg-gray-4" />
<Flex direction="column" gap="2" className="min-w-0 flex-1">
<Box className="h-[12px] w-[40%] animate-pulse rounded bg-gray-4" />
<Box className="h-[11px] w-[60%] animate-pulse rounded bg-gray-3" />
</Flex>
</Flex>
<Box className="h-[24px] w-[120px] shrink-0 animate-pulse rounded bg-gray-3" />
</Flex>
);
}

return (
<Flex
align="center"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
ComboboxList,
ComboboxTrigger,
} from "@posthog/quill";
import { Callout, Flex, Text } from "@radix-ui/themes";
import { Box, Callout, Flex, Text } from "@radix-ui/themes";
import type { SignalReportPriority, SlackChannelOption } from "@shared/types";
import { useMemo, useRef, useState } from "react";

Expand Down Expand Up @@ -76,10 +76,12 @@ function getSlackIntegrationLabel(integration: {

interface SignalSlackNotificationsSettingsProps {
channelComboboxModal?: boolean;
isLoading?: boolean;
}

export function SignalSlackNotificationsSettings({
channelComboboxModal = false,
isLoading = false,
}: SignalSlackNotificationsSettingsProps) {
const { slackIntegrations, hasSlackIntegration } = useIntegrationSelectors();
const { userAutonomyConfig, handleUpdateSlackNotifications } =
Expand Down Expand Up @@ -157,6 +159,23 @@ export function SignalSlackNotificationsSettings({
[slackIntegrations],
);

if (isLoading) {
return (
<Flex
direction="column"
gap="2"
pt="3"
className="border-(--gray-5) border-t border-dashed"
>
<Flex direction="column" gap="1">
<Box className="h-[14px] w-[160px] animate-pulse rounded bg-gray-4" />
<Box className="h-[11px] w-[80%] animate-pulse rounded bg-gray-3" />
</Flex>
<Box className="mt-1 h-[28px] w-[200px] animate-pulse rounded bg-gray-3" />
</Flex>
);
}

if (!hasSlackIntegration) {
return (
<Flex
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { DataSourceSetup } from "@features/inbox/components/DataSourceSetup";
import { SignalSourceToggles } from "@features/inbox/components/SignalSourceToggles";
import {
SignalSourceToggles,
SignalSourceTogglesSkeleton,
} from "@features/inbox/components/SignalSourceToggles";
import { useSignalSourceManager } from "@features/inbox/hooks/useSignalSourceManager";
import { SettingsOptionSelect } from "@features/settings/components/SettingsOptionSelect";
import { GitHubIntegrationSection } from "@features/settings/components/sections/GitHubIntegrationSection";
Expand Down Expand Up @@ -41,18 +44,12 @@ export function SignalSourcesSettings({
handleSetupComplete,
handleSetupCancel,
userAutonomyConfig,
userAutonomyConfigLoading,
handleUpdateUserAutonomyPriority,
} = useSignalSourceManager();

const { hasGithubIntegration } = useRepositoryIntegration();

if (isLoading) {
return (
<Text color="gray" className="text-[13px]">
Loading signal source configurations...
</Text>
);
}
const { hasGithubIntegration, isLoadingIntegrations } =
useRepositoryIntegration();

const userPriorityValue =
userAutonomyConfig?.autostart_priority ?? NEVER_VALUE;
Expand All @@ -65,40 +62,47 @@ export function SignalSourcesSettings({
improvements.
</Text>

<GitHubIntegrationSection hasGithubIntegration={hasGithubIntegration} />
<GitHubIntegrationSection
hasGithubIntegration={hasGithubIntegration}
isLoading={isLoadingIntegrations}
/>

<Tooltip
content="Connect code access to configure signal sources"
hidden={hasGithubIntegration}
>
<Box>
<Box
style={
!hasGithubIntegration
? { opacity: 0.45, pointerEvents: "none" }
: undefined
}
>
{setupSource ? (
<DataSourceSetup
source={setupSource}
onComplete={() => void handleSetupComplete()}
onCancel={handleSetupCancel}
/>
) : (
<SignalSourceToggles
value={displayValues}
onToggle={(source, enabled) =>
void handleToggle(source, enabled)
}
disabled={!hasGithubIntegration}
sourceStates={sourceStates}
onSetup={handleSetup}
/>
)}
{isLoading ? (
<SignalSourceTogglesSkeleton />
) : (
<Tooltip
content="Connect code access to configure signal sources"
hidden={hasGithubIntegration}
>
<Box>
<Box
style={
!hasGithubIntegration
? { opacity: 0.45, pointerEvents: "none" }
: undefined
}
>
{setupSource ? (
<DataSourceSetup
source={setupSource}
onComplete={() => void handleSetupComplete()}
onCancel={handleSetupCancel}
/>
) : (
<SignalSourceToggles
value={displayValues}
onToggle={(source, enabled) =>
void handleToggle(source, enabled)
}
disabled={!hasGithubIntegration}
sourceStates={sourceStates}
onSetup={handleSetup}
/>
)}
</Box>
</Box>
</Box>
</Tooltip>
</Tooltip>
)}
<Flex
direction="column"
gap="2"
Expand All @@ -115,20 +119,25 @@ export function SignalSourcesSettings({
&quot;Never&quot; to opt out.
</Text>
</Flex>
<SettingsOptionSelect
value={userPriorityValue}
options={USER_PRIORITY_OPTIONS}
ariaLabel="PR auto-start threshold"
className="min-w-[260px] max-w-[300px]"
onValueChange={(value) =>
void handleUpdateUserAutonomyPriority(
value === NEVER_VALUE ? null : value,
)
}
/>
{userAutonomyConfigLoading ? (
<Box className="h-[32px] w-[260px] animate-pulse rounded bg-gray-3" />
) : (
<SettingsOptionSelect
value={userPriorityValue}
options={USER_PRIORITY_OPTIONS}
ariaLabel="PR auto-start threshold"
className="min-w-[260px] max-w-[300px]"
onValueChange={(value) =>
void handleUpdateUserAutonomyPriority(
value === NEVER_VALUE ? null : value,
)
}
/>
)}
</Flex>
Comment on lines 106 to 137
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Auto-start threshold renders with a wrong default during load

Previously, when isLoading was true (signal source configs still pending), the entire component returned early — including the "Your PR auto-start threshold" section. Now that early return is removed, the threshold select renders immediately with userAutonomyConfig?.autostart_priority ?? NEVER_VALUE. While isLoading is still true, userAutonomyConfig is undefined, so the dropdown shows "Never — opt out of auto-assigned tasks" regardless of the user's actual saved preference. A user who quickly changes the dropdown during this window would overwrite their real setting with a value derived from an undefined config.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/code/src/renderer/features/settings/components/sections/SignalSourcesSettings.tsx
Line: 104-131

Comment:
**Auto-start threshold renders with a wrong default during load**

Previously, when `isLoading` was `true` (signal source configs still pending), the entire component returned early — including the "Your PR auto-start threshold" section. Now that early return is removed, the threshold select renders immediately with `userAutonomyConfig?.autostart_priority ?? NEVER_VALUE`. While `isLoading` is still `true`, `userAutonomyConfig` is `undefined`, so the dropdown shows "Never — opt out of auto-assigned tasks" regardless of the user's actual saved preference. A user who quickly changes the dropdown during this window would overwrite their real setting with a value derived from an `undefined` config.

How can I resolve this? If you propose a fix, please make it concise.

<SignalSlackNotificationsSettings
channelComboboxModal={slackNotificationsInModal}
isLoading={isLoadingIntegrations}
/>
</Flex>
);
Expand Down
1 change: 1 addition & 0 deletions apps/code/src/renderer/hooks/useIntegrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,7 @@ export function useRepositoryIntegration() {
repositories,
getIntegrationIdForRepo,
isRepoInIntegration,
isLoadingIntegrations: integrationsPending,
isLoadingRepos: integrationsPending || reposPending,
isRefreshingRepos,
refreshRepositories,
Expand Down
Loading