From 9f0b8f6bc6f882243a0696f8c5da29231ba679ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Flor=C3=AAncio?= Date: Tue, 26 May 2026 10:27:07 +0100 Subject: [PATCH] fix(settings): remove duplicate breadcrumbs and system sidebar badges (#1080) --- .../automations/automation-editor.tsx | 20 +-------- apps/web/components/page-topbar.tsx | 44 +++++++++--------- .../settings/settings-app-sidebar.tsx | 15 +------ .../settings/settings-layout-client.tsx | 45 ++++++++++++++----- 4 files changed, 57 insertions(+), 67 deletions(-) diff --git a/apps/web/components/automations/automation-editor.tsx b/apps/web/components/automations/automation-editor.tsx index cb8c339056..605b632bd3 100644 --- a/apps/web/components/automations/automation-editor.tsx +++ b/apps/web/components/automations/automation-editor.tsx @@ -8,7 +8,7 @@ import { Input } from "@kandev/ui/input"; import { Label } from "@kandev/ui/label"; import { Switch } from "@kandev/ui/switch"; import { Separator } from "@kandev/ui/separator"; -import { IconArrowLeft, IconTrash } from "@tabler/icons-react"; +import { IconTrash } from "@tabler/icons-react"; import { useAutomations } from "@/hooks/domains/settings/use-automations"; import { addTrigger, @@ -352,7 +352,6 @@ export function AutomationEditor({ workspaceId, automationId }: AutomationEditor return (
-
- - Automations -
- ); -} - function SettingsSection({ form, updateField, diff --git a/apps/web/components/page-topbar.tsx b/apps/web/components/page-topbar.tsx index 481f7f6848..6bbe740661 100644 --- a/apps/web/components/page-topbar.tsx +++ b/apps/web/components/page-topbar.tsx @@ -24,11 +24,11 @@ type PageTopbarProps = { /** Label for the parent breadcrumb (default: "Kandev") */ backLabel?: string; /** - * Optional middle crumb inserted between the back link and the title — use - * for nested sections (e.g. Home > Settings > Prompts). When omitted the - * breadcrumb is two segments wide. + * Optional middle crumbs inserted between the back link and the title — use + * for nested sections (e.g. Home > Settings > Automations > New). When + * omitted the breadcrumb is two segments wide. */ - parent?: { label: string; href: string }; + parents?: Array<{ label: string; href: string }>; /** Optional content rendered before the breadcrumb */ leading?: ReactNode; /** Optional content rendered at the visual center of the topbar */ @@ -66,14 +66,14 @@ function BackLink({ href, label }: { href: string; label: string }) { function TopbarBreadcrumb({ backHref, backLabel, - parent, + parents, title, subtitle, icon, }: { backHref: string; backLabel: string; - parent: { label: string; href: string } | undefined; + parents: Array<{ label: string; href: string }> | undefined; title: string; subtitle?: string; icon?: ReactNode; @@ -87,21 +87,19 @@ function TopbarBreadcrumb({ - {parent && ( - <> - - - - {parent.label} - - - - - - )} + {parents?.flatMap((p) => [ + + + + {p.label} + + + , + , + ])} {icon} @@ -128,7 +126,7 @@ export const PageTopbar = forwardRef(function Page icon, backHref = "/", backLabel = "Kandev", - parent, + parents, leading, center, leftActions, @@ -154,7 +152,7 @@ export const PageTopbar = forwardRef(function Page @@ -185,9 +180,6 @@ function SystemSidebarSection({ pathname }: { pathname: string }) { System - {badgeCount > 0 && ( - {badgeCount} - )} {items.map(({ href, label, Icon }) => ( @@ -197,11 +189,6 @@ function SystemSidebarSection({ pathname }: { pathname: string }) { {label} - {href === "/settings/system/status" && badgeCount > 0 && ( - - {badgeCount} - - )} ))} diff --git a/apps/web/components/settings/settings-layout-client.tsx b/apps/web/components/settings/settings-layout-client.tsx index bac428d4db..f4e98be1c2 100644 --- a/apps/web/components/settings/settings-layout-client.tsx +++ b/apps/web/components/settings/settings-layout-client.tsx @@ -42,18 +42,41 @@ function deriveCurrentPageLabel(pathname: string): string | null { return null; } +// Build the intermediate breadcrumb crumbs between the back link and the +// current page title. For workspace-scoped automation pages, inject an +// "Automations" crumb so the breadcrumb reads e.g. +// Home > Settings > Automations > New. +function deriveParents(pathname: string): Array<{ label: string; href: string }> { + const segments = pathname.split("/").filter(Boolean); + if (segments.length <= 1) return []; + + const parents: Array<{ label: string; href: string }> = [ + { label: "Settings", href: "/settings" }, + ]; + + const automationsMatch = pathname.match( + /^\/settings\/workspace\/([^/]+)\/automations(?:\/(.+))?/, + ); + if (automationsMatch && automationsMatch[2]) { + // Only inject the Automations crumb when we're on a sub-page (new or + // edit), not on the listing page itself — the listing page title is + // already "Automations". + parents.push({ + label: "Automations", + href: `/settings/workspace/${automationsMatch[1]}/automations`, + }); + } + + return parents; +} + export function SettingsLayoutClient({ children }: { children: React.ReactNode }) { const pathname = usePathname(); const isAgentDetail = pathname.startsWith("/settings/agents/") && pathname !== "/settings/agents"; if (isAgentDetail) { return ( - + {children} ); @@ -61,10 +84,10 @@ export function SettingsLayoutClient({ children }: { children: React.ReactNode } const pageLabel = deriveCurrentPageLabel(pathname); const title = pageLabel ?? "Settings"; - const parent = pageLabel ? { label: "Settings", href: "/settings" } : undefined; + const parents = deriveParents(pathname); return ( - + {children} ); @@ -74,13 +97,13 @@ function SettingsShell({ title, backHref, backLabel, - parent, + parents, children, }: { title: string; backHref: string; backLabel: string; - parent: { label: string; href: string } | undefined; + parents: Array<{ label: string; href: string }>; children: React.ReactNode; }) { return ( @@ -92,7 +115,7 @@ function SettingsShell({ title={title} backHref={backHref} backLabel={backLabel} - parent={parent} + parents={parents} className="h-16 border-b-0" leading={} />