import { Link, Outlet, useLocation } from "@tanstack/react-router"; import { useEffect, useRef, useState } from "react"; import { useAtomValue, useAtomSet } from "@effect/atom-react"; import * as AsyncResult from "effect/unstable/reactivity/AsyncResult"; import * as Exit from "effect/Exit"; import { useSourcesWithPending } from "@executor-js/react/api/optimistic"; import { useScope } from "@executor-js/react/api/scope-context"; import { Button } from "@executor-js/react/components/button"; import { Skeleton } from "@executor-js/react/components/skeleton"; import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@executor-js/react/components/dialog"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, } from "@executor-js/react/components/dropdown-menu"; import { SourceFavicon } from "@executor-js/react/components/source-favicon"; import { CommandPalette } from "@executor-js/react/components/command-palette"; import { authWriteKeys } from "@executor-js/react/api/reactivity-keys"; import { AUTH_PATHS } from "../auth/api"; import { organizationsAtom, switchOrganization, useAuth } from "./auth"; import { CreateOrganizationFields, useCreateOrganizationForm, } from "./components/create-organization-form"; // ── NavItem ────────────────────────────────────────────────────────────── function NavItem(props: { to: string; label: string; active: boolean; onNavigate?: () => void }) { return ( {props.label} ); } // ── SourceList ─────────────────────────────────────────────────────────── function SourceList(props: { pathname: string; onNavigate?: () => void }) { const scopeId = useScope(); const sources = useSourcesWithPending(scopeId); return AsyncResult.match(sources, { onInitial: () => (
{[80, 65, 72, 58, 68].map((w, i) => (
))}
), onFailure: () => (
No sources yet
), onSuccess: ({ value }) => value.length === 0 ? (
No sources yet
) : (
{value.map((s) => { const detailPath = `/sources/${s.id}`; const active = props.pathname === detailPath || props.pathname.startsWith(`${detailPath}/`); return ( {s.name} {s.kind} ); })}
), }); } // ── UserFooter ────────────────────────────────────────────────────────── function initialsFor(name: string | null, email: string) { if (name) { return name .split(" ") .map((n) => n[0]) .join("") .slice(0, 2) .toUpperCase(); } return email[0]!.toUpperCase(); } function Avatar(props: { url: string | null; name: string | null; email: string; size?: "sm" | "md"; }) { const size = props.size === "md" ? "size-8" : "size-7"; const text = props.size === "md" ? "text-sm" : "text-xs"; if (props.url) { return ; } return (
{initialsFor(props.name, props.email)}
); } function OrganizationSwitcherItems(props: { activeOrganizationId: string | null }) { const organizations = useAtomValue(organizationsAtom); const doSwitchOrganization = useAtomSet(switchOrganization, { mode: "promiseExit" }); const handleSwitch = async (organizationId: string) => { if (organizationId === props.activeOrganizationId) return; const exit = await doSwitchOrganization({ payload: { organizationId }, reactivityKeys: authWriteKeys, }); if (Exit.isSuccess(exit)) window.location.reload(); }; return AsyncResult.match(organizations, { onInitial: () => Loading…, onFailure: () => Failed to load organizations, onSuccess: ({ value }) => value.organizations.length === 0 ? ( No organizations ) : ( <> {value.organizations.map((organization: { id: string; name: string }) => { const isActive = organization.id === props.activeOrganizationId; return ( handleSwitch(organization.id)} className="text-xs" > {organization.name} {isActive && } ); })} ), }); } function CheckIcon() { return ( ); } function UserFooter() { const auth = useAuth(); const [createOrganizationOpen, setCreateOrganizationOpen] = useState(false); const suggestedOrganizationName = auth.status === "authenticated" && auth.user.name?.trim() !== "" && auth.user.name != null ? `${auth.user.name}'s Organization` : "New Organization"; const form = useCreateOrganizationForm({ defaultName: suggestedOrganizationName, onSuccess: () => window.location.reload(), }); if (auth.status !== "authenticated") return null; const openCreateOrganization = () => { form.reset(suggestedOrganizationName); setCreateOrganizationOpen(true); }; return (
{ setCreateOrganizationOpen(open); if (!open) form.reset(suggestedOrganizationName); }} > Organization {auth.organization?.name ?? "No organization"} { event.preventDefault(); openCreateOrganization(); }} > Create organization Signed in as

{auth.user.name ?? auth.user.email}

{auth.user.name && (

{auth.user.email}

)}
{ await fetch(AUTH_PATHS.logout, { method: "POST" }); window.location.href = "/"; }} > Sign out
Create organization Add another organization under your current account and switch into it immediately. { form.setName(name); if (form.error) form.setError(null); }} error={form.error} onSubmit={() => void form.submit()} />
); } // ── SidebarContent ─────────────────────────────────────────────────────── function SidebarContent(props: { pathname: string; onNavigate?: () => void; showBrand?: boolean }) { const isHome = props.pathname === "/"; const isSecrets = props.pathname === "/secrets"; const isConnections = props.pathname === "/connections"; const isPolicies = props.pathname === "/policies"; const isBilling = props.pathname === "/billing" || props.pathname.startsWith("/billing/"); const isOrg = props.pathname === "/org"; return ( <> {props.showBrand !== false && (
executor
)} ); } // ── Shell ───────────────────────────────────────────────────────────────── export function Shell() { const location = useLocation(); const pathname = location.pathname; const lastPathname = useRef(pathname); const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false); if (lastPathname.current !== pathname) { lastPathname.current = pathname; if (mobileSidebarOpen) setMobileSidebarOpen(false); } // Lock scroll when mobile sidebar open useEffect(() => { if (!mobileSidebarOpen) return; const prev = document.body.style.overflow; document.body.style.overflow = "hidden"; return () => { document.body.style.overflow = prev; }; }, [mobileSidebarOpen]); return (
{/* Desktop sidebar */} {/* Mobile sidebar overlay */} {mobileSidebarOpen && (
{/* oxlint-disable-next-line react/forbid-elements */}
setMobileSidebarOpen(false)} showBrand={false} />
)} {/* Main content */}
{/* Mobile top bar */}
executor
); }