UI polish: sidebar nav, Companies/Issues layout, assignee in issue defaults

- Sidebar: add Approvals and Companies links, remove temporary Design Guide link
- Companies: replace inline create form with 'New Company' button (opens onboarding)
- Issues: move filter tabs inline with page heading (consistent with Agents)
- DialogContext: add assigneeAgentId to NewIssueDefaults
- NewIssueDialog: wire assigneeAgentId default (pre-select assignee when opening
  from agent detail page)
- CommandPalette: minor cleanup
- App: add DesignGuide route (dev-only, no sidebar link)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Forgotten
2026-02-17 20:07:49 -06:00
parent 51780d1421
commit c0ae9423f0
7 changed files with 31 additions and 83 deletions

View File

@@ -2,7 +2,6 @@ import { Routes, Route, Navigate } from "react-router-dom";
import { Layout } from "./components/Layout";
import { Dashboard } from "./pages/Dashboard";
import { Companies } from "./pages/Companies";
import { Org } from "./pages/Org";
import { Agents } from "./pages/Agents";
import { AgentDetail } from "./pages/AgentDetail";
import { Projects } from "./pages/Projects";
@@ -16,6 +15,7 @@ import { Costs } from "./pages/Costs";
import { Activity } from "./pages/Activity";
import { Inbox } from "./pages/Inbox";
import { MyIssues } from "./pages/MyIssues";
import { DesignGuide } from "./pages/DesignGuide";
export function App() {
return (
@@ -24,7 +24,7 @@ export function App() {
<Route index element={<Navigate to="/dashboard" replace />} />
<Route path="dashboard" element={<Dashboard />} />
<Route path="companies" element={<Companies />} />
<Route path="org" element={<Org />} />
<Route path="org" element={<Navigate to="/agents" replace />} />
<Route path="agents" element={<Agents />} />
<Route path="agents/:agentId" element={<AgentDetail />} />
<Route path="projects" element={<Projects />} />
@@ -38,6 +38,7 @@ export function App() {
<Route path="activity" element={<Activity />} />
<Route path="inbox" element={<Inbox />} />
<Route path="my-issues" element={<MyIssues />} />
<Route path="design-guide" element={<DesignGuide />} />
</Route>
</Routes>
);

View File

@@ -25,7 +25,6 @@ import {
Inbox,
DollarSign,
History,
GitBranch,
SquarePen,
Plus,
} from "lucide-react";
@@ -114,10 +113,6 @@ export function CommandPalette() {
<History className="mr-2 h-4 w-4" />
Activity
</CommandItem>
<CommandItem onSelect={() => go("/org")}>
<GitBranch className="mr-2 h-4 w-4" />
Org Chart
</CommandItem>
</CommandGroup>
<CommandSeparator />

View File

@@ -94,6 +94,7 @@ export function NewIssueDialog() {
setStatus(newIssueDefaults.status ?? "todo");
setPriority(newIssueDefaults.priority ?? "");
setProjectId(newIssueDefaults.projectId ?? "");
setAssigneeId(newIssueDefaults.assigneeAgentId ?? "");
}
}, [newIssueOpen, newIssueDefaults]);

View File

@@ -4,15 +4,14 @@ import {
Hexagon,
Target,
LayoutDashboard,
GitBranch,
Bot,
DollarSign,
History,
Search,
SquarePen,
Building2,
ListTodo,
LayoutList,
ShieldCheck,
Building2,
} from "lucide-react";
import { CompanySwitcher } from "./CompanySwitcher";
import { SidebarSection } from "./SidebarSection";
@@ -70,8 +69,8 @@ export function Sidebar() {
<SidebarSection label="Company">
<SidebarNavItem to="/dashboard" label="Dashboard" icon={LayoutDashboard} />
<SidebarNavItem to="/org" label="Org Chart" icon={GitBranch} />
<SidebarNavItem to="/agents" label="Agents" icon={Bot} />
<SidebarNavItem to="/approvals" label="Approvals" icon={ShieldCheck} />
<SidebarNavItem to="/costs" label="Costs" icon={DollarSign} />
<SidebarNavItem to="/activity" label="Activity" icon={History} />
<SidebarNavItem to="/companies" label="Companies" icon={Building2} />

View File

@@ -4,6 +4,7 @@ interface NewIssueDefaults {
status?: string;
priority?: string;
projectId?: string;
assigneeAgentId?: string;
}
interface DialogContextValue {

View File

@@ -1,31 +1,26 @@
import { useState, useEffect } from "react";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { useCompany } from "../context/CompanyContext";
import { useDialog } from "../context/DialogContext";
import { useBreadcrumbs } from "../context/BreadcrumbContext";
import { companiesApi } from "../api/companies";
import { queryKeys } from "../lib/queryKeys";
import { formatCents } from "../lib/utils";
import { Card, CardContent } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Pencil, Check, X } from "lucide-react";
import { Pencil, Check, X, Plus } from "lucide-react";
export function Companies() {
const {
companies,
selectedCompanyId,
setSelectedCompanyId,
createCompany,
loading,
error,
} = useCompany();
const { openOnboarding } = useDialog();
const { setBreadcrumbs } = useBreadcrumbs();
const queryClient = useQueryClient();
const [name, setName] = useState("");
const [description, setDescription] = useState("");
const [budget, setBudget] = useState("0");
const [submitting, setSubmitting] = useState(false);
const [submitError, setSubmitError] = useState<string | null>(null);
// Inline edit state
const [editingId, setEditingId] = useState<string | null>(null);
@@ -44,28 +39,6 @@ export function Companies() {
setBreadcrumbs([{ label: "Companies" }]);
}, [setBreadcrumbs]);
async function onSubmit(e: React.FormEvent) {
e.preventDefault();
if (!name.trim()) return;
setSubmitting(true);
setSubmitError(null);
try {
await createCompany({
name: name.trim(),
description: description.trim() || null,
budgetMonthlyCents: Number(budget) || 0,
});
setName("");
setDescription("");
setBudget("0");
} catch (err) {
setSubmitError(err instanceof Error ? err.message : "Failed to create company");
} finally {
setSubmitting(false);
}
}
function startEdit(companyId: string, currentName: string) {
setEditingId(companyId);
setEditName(currentName);
@@ -83,39 +56,16 @@ export function Companies() {
return (
<div className="space-y-6">
<div className="flex items-center justify-between">
<div>
<h2 className="text-lg font-semibold">Companies</h2>
<p className="text-sm text-muted-foreground">Create and manage your companies.</p>
<p className="text-sm text-muted-foreground">Manage your companies.</p>
</div>
<Card>
<CardContent className="p-4 space-y-3">
<h3 className="text-sm font-semibold">Create Company</h3>
<form onSubmit={onSubmit} className="space-y-3">
<div className="grid md:grid-cols-3 gap-3">
<Input
placeholder="Company name"
value={name}
onChange={(e) => setName(e.target.value)}
/>
<Input
placeholder="Description"
value={description}
onChange={(e) => setDescription(e.target.value)}
/>
<Input
placeholder="Monthly budget (cents)"
value={budget}
onChange={(e) => setBudget(e.target.value.replace(/[^0-9]/g, ""))}
/>
</div>
{submitError && <p className="text-sm text-destructive">{submitError}</p>}
<Button type="submit" size="sm" disabled={submitting}>
{submitting ? "Creating..." : "Create Company"}
<Button size="sm" onClick={openOnboarding}>
<Plus className="h-3.5 w-3.5 mr-1.5" />
New Company
</Button>
</form>
</CardContent>
</Card>
</div>
<div className="h-6">
{loading && <p className="text-sm text-muted-foreground">Loading companies...</p>}

View File

@@ -89,13 +89,8 @@ export function Issues() {
return (
<div className="space-y-4">
<div className="flex items-center justify-between">
<div className="flex items-center gap-4">
<h2 className="text-lg font-semibold">Issues</h2>
<Button size="sm" onClick={() => openNewIssue()}>
<Plus className="h-4 w-4 mr-1" />
New Issue
</Button>
</div>
<Tabs value={tab} onValueChange={(v) => setTab(v as TabFilter)}>
<TabsList>
<TabsTrigger value="all">All Issues</TabsTrigger>
@@ -104,6 +99,12 @@ export function Issues() {
<TabsTrigger value="done">Done</TabsTrigger>
</TabsList>
</Tabs>
</div>
<Button size="sm" onClick={() => openNewIssue()}>
<Plus className="h-4 w-4 mr-1" />
New Issue
</Button>
</div>
{isLoading && <p className="text-sm text-muted-foreground">Loading...</p>}
{error && <p className="text-sm text-destructive">{error.message}</p>}