Skip to content

Commit 7438f5a

Browse files
authored
Address settings navigation review feedback
Generated-By: PostHog Code Task-Id: 5579dbc2-d5dd-440f-8fb5-3cbd00ed0957
1 parent e42e8dc commit 7438f5a

10 files changed

Lines changed: 126 additions & 93 deletions

File tree

packages/ui/src/features/inbox/components/ConfigureAgentsSection.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,8 @@ export function ConfigureAgentsSection() {
212212
description="External tools responders can read from. PostHog data is always available; this is everything else."
213213
>
214214
<Link
215-
to="/mcp-servers"
215+
to="/settings/$category"
216+
params={{ category: "mcp-servers" }}
216217
onClick={() =>
217218
track(ANALYTICS_EVENTS.AGENTS_ACTION, {
218219
action_type: "open_mcp_servers",

packages/ui/src/features/scouts/components/ScoutHelperSkillLinks.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ export function ScoutHelperSkillLinks({ surface }: { surface: ScoutSurface }) {
2323
<span key={skill.name}>
2424
{index > 0 ? " · " : null}
2525
<Link
26-
to="/skills"
26+
to="/settings/$category"
27+
params={{ category: "skills" }}
2728
onClick={() => {
2829
track(ANALYTICS_EVENTS.SCOUT_ACTION, {
2930
action_type: "open_helper_skill",

packages/ui/src/features/settings/components/SettingsPanel.tsx

Lines changed: 9 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
TreeStructure,
2323
Wrench,
2424
} from "@phosphor-icons/react";
25+
import { MenuLabel } from "@posthog/quill";
2526
import { BILLING_FLAG } from "@posthog/shared";
2627
import { useOptionalAuthenticatedClient } from "@posthog/ui/features/auth/authClient";
2728
import { useAuthStateValue } from "@posthog/ui/features/auth/store";
@@ -31,6 +32,7 @@ import { getUserInitials } from "@posthog/ui/features/auth/userInitials";
3132
import { useFeatureFlag } from "@posthog/ui/features/feature-flags/useFeatureFlag";
3233
import { SettingsPageContent } from "@posthog/ui/features/settings/components/SettingsPageContent";
3334
import { closeSettings } from "@posthog/ui/features/settings/hooks/useOpenSettings";
35+
import { getHiddenSettingsCategories } from "@posthog/ui/features/settings/settingsVisibility";
3436
import { useSettingsPageStore } from "@posthog/ui/features/settings/stores/settingsPageStore";
3537
import type { SettingsCategory } from "@posthog/ui/features/settings/types";
3638
import { useSpendAnalysisEnabled } from "@posthog/ui/features/usage/useSpendAnalysisEnabled";
@@ -122,43 +124,6 @@ const SIDEBAR_GROUPS: SidebarGroup[] = [
122124

123125
const SIDEBAR_ITEMS = SIDEBAR_GROUPS.flatMap((group) => group.items);
124126

125-
// Settings that only make sense with a local filesystem/host (local worktrees,
126-
// terminal, the local `claude` CLI, the desktop app itself). Hidden on the
127-
// cloud-only web host.
128-
const LOCAL_ONLY_CATEGORIES: ReadonlySet<SettingsCategory> = new Set([
129-
"workspaces",
130-
"worktrees",
131-
"terminal",
132-
"claude-code",
133-
"discord",
134-
"updates",
135-
]);
136-
137-
interface SettingsVisibility {
138-
billingEnabled: boolean;
139-
spendAnalysisEnabled: boolean;
140-
localWorkspaces: boolean;
141-
}
142-
143-
function getHiddenSettingsCategories({
144-
billingEnabled,
145-
spendAnalysisEnabled,
146-
localWorkspaces,
147-
}: SettingsVisibility): ReadonlySet<SettingsCategory> {
148-
const hiddenCategories = new Set<SettingsCategory>();
149-
150-
if (!billingEnabled && !spendAnalysisEnabled) {
151-
hiddenCategories.add("plan-usage");
152-
}
153-
if (!localWorkspaces) {
154-
for (const category of LOCAL_ONLY_CATEGORIES) {
155-
hiddenCategories.add(category);
156-
}
157-
}
158-
159-
return hiddenCategories;
160-
}
161-
162127
export interface SettingsPanelProps {
163128
/**
164129
* Override the active category. Defaults to the `$category` URL param
@@ -206,10 +171,11 @@ export function SettingsPanel({
206171
// Guard direct navigation (URL, deep link, programmatic openSettings) to a
207172
// category hidden on this host. Fall back to General so a hidden section is
208173
// never rendered.
209-
const resolvedCategory: SettingsCategory =
210-
!localWorkspaces && LOCAL_ONLY_CATEGORIES.has(activeCategory)
211-
? "general"
212-
: activeCategory;
174+
const resolvedCategory: SettingsCategory = hiddenCategories.has(
175+
activeCategory,
176+
)
177+
? "general"
178+
: activeCategory;
213179
const activeSidebarCategory: SettingsCategory =
214180
resolvedCategory === "cloud-environments"
215181
? "environments"
@@ -266,9 +232,9 @@ export function SettingsPanel({
266232
<div className="flex flex-col gap-3 py-2">
267233
{sidebarGroups.map((group) => (
268234
<div key={group.label}>
269-
<Text className="px-3 pb-1 font-medium text-[10px] text-gray-9 uppercase tracking-wider">
235+
<MenuLabel className="px-3 pb-1 text-gray-9">
270236
{group.label}
271-
</Text>
237+
</MenuLabel>
272238
{group.items.map((item) => {
273239
const isActive = activeSidebarCategory === item.id;
274240
return (
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { describe, expect, it } from "vitest";
2+
import { getHiddenSettingsCategories } from "./settingsVisibility";
3+
4+
describe("getHiddenSettingsCategories", () => {
5+
it.each([
6+
{
7+
name: "shows all categories when every capability is available",
8+
input: {
9+
billingEnabled: true,
10+
spendAnalysisEnabled: true,
11+
localWorkspaces: true,
12+
},
13+
expected: [],
14+
},
15+
{
16+
name: "hides plan and usage without billing or spend analysis",
17+
input: {
18+
billingEnabled: false,
19+
spendAnalysisEnabled: false,
20+
localWorkspaces: true,
21+
},
22+
expected: ["plan-usage"],
23+
},
24+
{
25+
name: "hides host-specific categories without local workspaces",
26+
input: {
27+
billingEnabled: true,
28+
spendAnalysisEnabled: true,
29+
localWorkspaces: false,
30+
},
31+
expected: [
32+
"workspaces",
33+
"worktrees",
34+
"terminal",
35+
"claude-code",
36+
"discord",
37+
"updates",
38+
],
39+
},
40+
])("$name", ({ input, expected }) => {
41+
expect([...getHiddenSettingsCategories(input)]).toEqual(expected);
42+
});
43+
});
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import type { SettingsCategory } from "@posthog/ui/features/settings/types";
2+
3+
// Settings that only make sense with a local filesystem/host (local worktrees,
4+
// terminal, the local `claude` CLI, the desktop app itself). Hidden on the
5+
// cloud-only web host.
6+
const LOCAL_ONLY_CATEGORIES: ReadonlySet<SettingsCategory> = new Set([
7+
"workspaces",
8+
"worktrees",
9+
"terminal",
10+
"claude-code",
11+
"discord",
12+
"updates",
13+
]);
14+
15+
interface SettingsVisibility {
16+
billingEnabled: boolean;
17+
spendAnalysisEnabled: boolean;
18+
localWorkspaces: boolean;
19+
}
20+
21+
export function getHiddenSettingsCategories({
22+
billingEnabled,
23+
spendAnalysisEnabled,
24+
localWorkspaces,
25+
}: SettingsVisibility): ReadonlySet<SettingsCategory> {
26+
const hiddenCategories = new Set<SettingsCategory>();
27+
28+
if (!billingEnabled && !spendAnalysisEnabled) {
29+
hiddenCategories.add("plan-usage");
30+
}
31+
if (!localWorkspaces) {
32+
for (const category of LOCAL_ONLY_CATEGORIES) {
33+
hiddenCategories.add(category);
34+
}
35+
}
36+
37+
return hiddenCategories;
38+
}

packages/ui/src/router/navigationBridge.ts

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -155,10 +155,6 @@ export function navigateToScoutFindings(): void {
155155
void getRouterOrNull()?.navigate({ to: "/code/agents/scouts/findings" });
156156
}
157157

158-
export function navigateToAgents(): void {
159-
void getRouterOrNull()?.navigate({ to: "/code/agents" });
160-
}
161-
162158
export function navigateToApproval(requestId: string): void {
163159
void getRouterOrNull()?.navigate({
164160
to: "/code/agents/applications/approvals",
@@ -177,14 +173,6 @@ export function navigateToCommandCenter(): void {
177173
track(ANALYTICS_EVENTS.COMMAND_CENTER_VIEWED);
178174
}
179175

180-
export function navigateToSkills(): void {
181-
void getRouterOrNull()?.navigate({ to: "/skills" });
182-
}
183-
184-
export function navigateToMcpServers(): void {
185-
void getRouterOrNull()?.navigate({ to: "/mcp-servers" });
186-
}
187-
188176
// Channels-space mirrors. These render the same shared views as their /code (or
189177
// top-level) counterparts but under /website, so navigating from the channels
190178
// sidebar keeps the channels chrome instead of switching back to Code. The
@@ -203,14 +191,6 @@ export function navigateToCanvas(): void {
203191
void getRouterOrNull()?.navigate({ to: "/website" });
204192
}
205193

206-
export function navigateToWebsiteSkills(): void {
207-
void getRouterOrNull()?.navigate({ to: "/website/skills" });
208-
}
209-
210-
export function navigateToWebsiteMcpServers(): void {
211-
void getRouterOrNull()?.navigate({ to: "/website/mcp-servers" });
212-
}
213-
214194
export function navigateToWebsiteCommandCenter(): void {
215195
void getRouterOrNull()?.navigate({ to: "/website/command-center" });
216196
// Parity with navigateToCommandCenter's analytics tracking.
Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import { McpServersView } from "@posthog/ui/features/mcp-servers/components/McpServersView";
2-
import {
3-
AppPageSkeleton,
4-
withRouteSkeleton,
5-
} from "@posthog/ui/router/routeSkeletons";
6-
import { createFileRoute } from "@tanstack/react-router";
1+
import { createFileRoute, redirect } from "@tanstack/react-router";
72

83
export const Route = createFileRoute("/mcp-servers")({
9-
component: McpServersView,
10-
...withRouteSkeleton(AppPageSkeleton),
4+
beforeLoad: () => {
5+
throw redirect({
6+
to: "/settings/$category",
7+
params: { category: "mcp-servers" },
8+
replace: true,
9+
});
10+
},
1111
});
Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import { SkillsView } from "@posthog/ui/features/skills/SkillsView";
2-
import {
3-
AppPageSkeleton,
4-
withRouteSkeleton,
5-
} from "@posthog/ui/router/routeSkeletons";
6-
import { createFileRoute } from "@tanstack/react-router";
1+
import { createFileRoute, redirect } from "@tanstack/react-router";
72

83
export const Route = createFileRoute("/skills")({
9-
component: SkillsView,
10-
...withRouteSkeleton(AppPageSkeleton),
4+
beforeLoad: () => {
5+
throw redirect({
6+
to: "/settings/$category",
7+
params: { category: "skills" },
8+
replace: true,
9+
});
10+
},
1111
});
Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
import { McpServersView } from "@posthog/ui/features/mcp-servers/components/McpServersView";
2-
import { createFileRoute } from "@tanstack/react-router";
1+
import { createFileRoute, redirect } from "@tanstack/react-router";
32

4-
// Channels-space mirror of /mcp-servers. Renders the same shared McpServersView
5-
// so the page stays single-source; only the route entry is duplicated so
6-
// navigating here keeps the channels chrome (rail + channel sidebar).
73
export const Route = createFileRoute("/website/mcp-servers")({
8-
component: McpServersView,
4+
beforeLoad: () => {
5+
throw redirect({
6+
to: "/settings/$category",
7+
params: { category: "mcp-servers" },
8+
replace: true,
9+
});
10+
},
911
});
Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
import { SkillsView } from "@posthog/ui/features/skills/SkillsView";
2-
import { createFileRoute } from "@tanstack/react-router";
1+
import { createFileRoute, redirect } from "@tanstack/react-router";
32

4-
// Channels-space mirror of /skills. Renders the same shared SkillsView so the
5-
// page stays single-source; only the route entry is duplicated so navigating
6-
// here keeps the channels chrome (rail + channel sidebar).
73
export const Route = createFileRoute("/website/skills")({
8-
component: SkillsView,
4+
beforeLoad: () => {
5+
throw redirect({
6+
to: "/settings/$category",
7+
params: { category: "skills" },
8+
replace: true,
9+
});
10+
},
911
});

0 commit comments

Comments
 (0)