User code no longer execs in the engine. A pool of persistent worker subprocesses speaks one JSON object per line; the controller installs a proxy as the node's function, so every execution path funnels through it and the pipeline is untouched. A crash costs one subprocess, a per-node timeout is a kill, and cancelling from the canvas is that same kill. The workers run a venv of the user's own on the data volume, filled from a pip manifest versioned beside the flows. Applying it retires the workers and rebuilds, so a package lands without restarting the engine. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017MeiWk3Yq12n2pTvnQWYvt
79 lines
2.6 KiB
TypeScript
79 lines
2.6 KiB
TypeScript
import {
|
|
Bell,
|
|
Home,
|
|
KeyRound,
|
|
LayoutDashboard,
|
|
LogOut,
|
|
Package,
|
|
Settings,
|
|
Users,
|
|
Workflow,
|
|
} from "lucide-react"
|
|
|
|
import { Logo } from "@/components/Common/Logo"
|
|
import {
|
|
Sidebar,
|
|
SidebarContent,
|
|
SidebarFooter,
|
|
SidebarHeader,
|
|
SidebarTrigger,
|
|
} from "@/components/ui/sidebar"
|
|
import useAuth from "@/hooks/useAuth"
|
|
import { type Item, Main } from "./Main"
|
|
|
|
const baseItems: Item[] = [
|
|
// "Home" rather than "Dashboard": dashboards are their own thing now.
|
|
{ icon: Home, title: "Home", path: "/" },
|
|
{ icon: Workflow, title: "Flows", path: "/flows" },
|
|
{ icon: LayoutDashboard, title: "Dashboards", path: "/dashboards" },
|
|
// Both are engine-wide operator settings rather than personal ones, so they
|
|
// sit here and not among the per-user tabs under Settings.
|
|
{ icon: KeyRound, title: "Secrets", path: "/secrets" },
|
|
{ icon: Package, title: "Modules", path: "/modules" },
|
|
{ icon: Bell, title: "Alerts", path: "/alerts" },
|
|
]
|
|
|
|
export function AppSidebar() {
|
|
const { user: currentUser, logout } = useAuth()
|
|
|
|
const items = currentUser?.is_superuser
|
|
? [...baseItems, { icon: Users, title: "Admin", path: "/admin" }]
|
|
: baseItems
|
|
|
|
const footerItems: Item[] = [
|
|
{ icon: Settings, title: "Settings", path: "/settings" },
|
|
{ icon: LogOut, title: "Log Out", onClick: logout },
|
|
]
|
|
|
|
return (
|
|
// Floating frosted chrome over whatever surface the shell paints; see the
|
|
// root DESIGN-GUIDELINES.md → Shells and → Overlay surfaces & content chips.
|
|
<Sidebar
|
|
collapsible="icon"
|
|
variant="floating"
|
|
className="[&>[data-sidebar=sidebar]]:bg-card/80 [&>[data-sidebar=sidebar]]:backdrop-blur-md [&>[data-sidebar=sidebar]]:shadow-e2"
|
|
>
|
|
<SidebarHeader className="px-4 py-6 group-data-[collapsible=icon]:px-0 group-data-[collapsible=icon]:items-center">
|
|
<div className="flex w-full items-center justify-between gap-2 group-data-[collapsible=icon]:justify-center">
|
|
{/* Collapsed, the rail has room for one thing, and that is the way
|
|
back out. */}
|
|
<span className="group-data-[collapsible=icon]:hidden">
|
|
<Logo variant="responsive" />
|
|
</span>
|
|
{/* On a phone the sidebar is a sheet with its own way in and out. */}
|
|
<SidebarTrigger className="hidden shrink-0 text-muted-foreground md:inline-flex" />
|
|
</div>
|
|
</SidebarHeader>
|
|
<SidebarContent>
|
|
<Main items={items} />
|
|
</SidebarContent>
|
|
{/* Main already pads horizontally; the footer only adds the bottom gap. */}
|
|
<SidebarFooter className="px-0">
|
|
<Main items={footerItems} />
|
|
</SidebarFooter>
|
|
</Sidebar>
|
|
)
|
|
}
|
|
|
|
export default AppSidebar
|