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
8 changes: 7 additions & 1 deletion apps/code/src/renderer/components/GlobalEventHandlers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useSidebarStore } from "@features/sidebar/stores/sidebarStore";
import { useTasks } from "@features/tasks/hooks/useTasks";
import { useFocusWorkspace } from "@features/workspace/hooks/useFocusWorkspace";
import { useWorkspaces } from "@features/workspace/hooks/useWorkspace";
import { useFeatureFlag } from "@hooks/useFeatureFlag";
import { SHORTCUTS } from "@renderer/constants/keyboard-shortcuts";
import { useTRPC } from "@renderer/trpc";
import type { Task } from "@shared/types";
Expand Down Expand Up @@ -170,10 +171,15 @@ export function GlobalEventHandlers({
setReviewMode(currentTaskId, mode === "closed" ? "split" : "closed");
}, [currentTaskId, getReviewMode, setReviewMode]);

const inboxEnabled = useFeatureFlag("posthog-code-inbox");

useHotkeys(SHORTCUTS.TOGGLE_LEFT_SIDEBAR, toggleLeftSidebar, globalOptions);
useHotkeys(SHORTCUTS.TOGGLE_REVIEW_PANEL, handleToggleReview, globalOptions);
useHotkeys(SHORTCUTS.SHORTCUTS_SHEET, onToggleShortcutsSheet, globalOptions);
useHotkeys(SHORTCUTS.INBOX, navigateToInbox, globalOptions);
useHotkeys(SHORTCUTS.INBOX, navigateToInbox, {
...globalOptions,
enabled: inboxEnabled,
});
useHotkeys(SHORTCUTS.PREV_TASK, handlePrevTask, globalOptions, [
handlePrevTask,
]);
Expand Down
10 changes: 9 additions & 1 deletion apps/code/src/renderer/components/KeyboardShortcutsSheet.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useFeatureFlag } from "@hooks/useFeatureFlag";
import { Box, Dialog, Flex, Text } from "@radix-ui/themes";
import {
CATEGORY_LABELS,
Expand Down Expand Up @@ -130,7 +131,14 @@ function ShortcutsHeader() {
}

export function KeyboardShortcutsList() {
const shortcutsByCategory = useMemo(() => getShortcutsByCategory(), []);
const inboxEnabled = useFeatureFlag("posthog-code-inbox");
const shortcutsByCategory = useMemo(() => {
const grouped = getShortcutsByCategory();
if (!inboxEnabled) {
grouped.navigation = grouped.navigation.filter((s) => s.id !== "inbox");
}
return grouped;
}, [inboxEnabled]);

const categoryOrder: ShortcutCategory[] = [
"general",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useFeatureFlag } from "@hooks/useFeatureFlag";
import {
ArrowRight,
ChartLine,
Expand All @@ -8,37 +9,42 @@ import {
} from "@phosphor-icons/react";
import { Button, Flex, Text } from "@radix-ui/themes";
import explorerHog from "@renderer/assets/images/hedgehogs/explorer-hog.png";
import { useCallback, useEffect, useRef, useState } from "react";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { FeatureListItem } from "./FeatureListItem";
import { OnboardingHogTip } from "./OnboardingHogTip";
import { StepActions } from "./StepActions";

const FEATURES = [
const ALL_FEATURES = [
{
id: "signals-inbox",
icon: <Tray size={24} />,
title: "Your signals inbox",
description:
"Automatically surfaces the highest-impact work from your product data so you always know what to do next.",
},
{
id: "product-data",
icon: <ChartLine size={24} />,
title: "Product data as context",
description:
"Your agents have context from your analytics, session replays and feature flags built in.",
},
{
id: "any-model",
icon: <Robot size={24} />,
title: "Any model, any harness",
description:
"Bring your own agent framework or use our built-in harnesses. Swap models without changing your workflow.",
},
{
id: "ship-work",
icon: <Cloud size={24} />,
title: "Ship work, not messages",
description:
"Run tasks in parallel across local and cloud environments. Work gets done whether you're watching or not.",
},
{
id: "review-ship",
icon: <GitPullRequest size={24} />,
title: "Review and ship with confidence",
description:
Expand All @@ -51,18 +57,26 @@ interface WelcomeScreenProps {
}

const CYCLE_INTERVAL_MS = 2500;
const CYCLE_START_DELAY_MS = FEATURES.length * 100 + 400;
const CYCLE_START_DELAY_MS = ALL_FEATURES.length * 100 + 400;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 CYCLE_START_DELAY_MS ignores runtime feature count

This constant is computed at module load using ALL_FEATURES.length (5), so when inbox is disabled the animation intro delay is 900 ms instead of the intended 800 ms (4 items × 100 ms + 400 ms). The difference is imperceptible, but the intent was clearly to match the number of rendered items. Consider deriving the delay inside the component from features.length instead.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/code/src/renderer/features/onboarding/components/WelcomeScreen.tsx
Line: 60

Comment:
**`CYCLE_START_DELAY_MS` ignores runtime feature count**

This constant is computed at module load using `ALL_FEATURES.length` (5), so when inbox is disabled the animation intro delay is 900 ms instead of the intended 800 ms (4 items × 100 ms + 400 ms). The difference is imperceptible, but the intent was clearly to match the number of rendered items. Consider deriving the delay inside the component from `features.length` instead.

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


export function WelcomeScreen({ onNext }: WelcomeScreenProps) {
const inboxEnabled = useFeatureFlag("posthog-code-inbox");
const features = useMemo(
() =>
inboxEnabled
? ALL_FEATURES
: ALL_FEATURES.filter((f) => f.id !== "signals-inbox"),
[inboxEnabled],
);
const [activeIndex, setActiveIndex] = useState(-1);
const timerRef = useRef<ReturnType<typeof setInterval>>(null);

const startCycling = useCallback(() => {
if (timerRef.current) clearInterval(timerRef.current);
timerRef.current = setInterval(() => {
setActiveIndex((prev) => (prev + 1) % FEATURES.length);
setActiveIndex((prev) => (prev + 1) % features.length);
}, CYCLE_INTERVAL_MS);
}, []);
}, [features.length]);

useEffect(() => {
const timeout = setTimeout(() => {
Expand Down Expand Up @@ -126,7 +140,7 @@ export function WelcomeScreen({ onNext }: WelcomeScreenProps) {
</Flex>

<Flex direction="column" style={{ width: "100%", gap: 8 }}>
{FEATURES.map((feature, index) => (
{features.map((feature, index) => (
<FeatureListItem
key={feature.title}
Comment on lines 144 to 145
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Prefer stable id as React list key

Each item in ALL_FEATURES now has a dedicated id field. Using it as the list key is more robust than relying on the display title string.

Suggested change
<FeatureListItem
key={feature.title}
<FeatureListItem
key={feature.id}
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/code/src/renderer/features/onboarding/components/WelcomeScreen.tsx
Line: 144-145

Comment:
**Prefer stable `id` as React list key**

Each item in `ALL_FEATURES` now has a dedicated `id` field. Using it as the list key is more robust than relying on the display title string.

```suggestion
                <FeatureListItem
                  key={feature.id}
```

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

icon={feature.icon}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useAuthStateValue } from "@features/auth/hooks/authQueries";
import { useOnboardingStore } from "@features/onboarding/stores/onboardingStore";
import { useFeatureFlag } from "@hooks/useFeatureFlag";
import { trpcClient } from "@renderer/trpc/client";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { ONBOARDING_STEPS, type OnboardingStep } from "../types";
Expand Down Expand Up @@ -78,13 +79,18 @@ export function useOnboardingFlow() {
);

const hasCodeAccess = useAuthStateValue((state) => state.hasCodeAccess);
const inboxEnabled = useFeatureFlag("posthog-code-inbox");

const activeSteps = useMemo(() => {
let steps = ONBOARDING_STEPS as OnboardingStep[];
if (hasCodeAccess === true) {
return ONBOARDING_STEPS.filter((s) => s !== "invite-code");
steps = steps.filter((s) => s !== "invite-code");
}
return ONBOARDING_STEPS;
}, [hasCodeAccess]);
if (!inboxEnabled) {
steps = steps.filter((s) => s !== "signals");
}
return steps;
}, [hasCodeAccess, inboxEnabled]);

useEffect(() => {
if (!activeSteps.includes(currentStep)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,14 +129,17 @@ export function SettingsDialog() {
const { data: user } = useCurrentUser({ client });
const { seat, planLabel } = useSeat();
const billingEnabled = useFeatureFlag("posthog-code-billing");
const inboxEnabled = useFeatureFlag("posthog-code-inbox");
const logoutMutation = useLogoutMutation();

const sidebarItems = useMemo(
() =>
billingEnabled
? SIDEBAR_ITEMS
: SIDEBAR_ITEMS.filter((item) => item.id !== "plan-usage"),
[billingEnabled],
SIDEBAR_ITEMS.filter((item) => {
if (item.id === "plan-usage" && !billingEnabled) return false;
if (item.id === "signals" && !inboxEnabled) return false;
return true;
}),
[billingEnabled, inboxEnabled],
);

useHotkeys("escape", close, {
Expand Down
Loading