feat: maintenance flows frontend foundation - types, API clients, sidebar, library filter

- Add maintenance.ts types: TargetEntry, TargetList, MaintenanceSchedule, BatchLaunch
- Add targetListsApi and maintenanceSchedulesApi/batchLaunchApi clients
- Extend TreeType union with 'maintenance' in tree.ts
- Update getTreeNavigatePath/getTreeEditorPath in routing.ts for maintenance
- Sidebar: track maintenance count and add Maintenance sub-nav item
- TreeLibraryPage: add maintenance to typeFilter state, URL sync, and tab buttons
- TreeGridView, TreeListView, TreeTableView: add amber Wrench maintenance badge

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
chihlasm
2026-02-17 14:06:36 -05:00
parent 829b7cf5a7
commit 8441a8dbaf
12 changed files with 161 additions and 15 deletions

View File

@@ -37,14 +37,14 @@ export function TreeLibraryPage() {
// Read type filter from URL query params (e.g. /trees?type=procedural)
const urlType = searchParams.get('type')
const [typeFilter, setTypeFilter] = useState<'all' | 'troubleshooting' | 'procedural'>(
urlType === 'troubleshooting' || urlType === 'procedural' ? urlType : 'all'
const [typeFilter, setTypeFilter] = useState<'all' | 'troubleshooting' | 'procedural' | 'maintenance'>(
urlType === 'troubleshooting' || urlType === 'procedural' || urlType === 'maintenance' ? urlType : 'all'
)
// Sync filters when URL changes (e.g. clicking sidebar categories/tags or nav sub-items)
useEffect(() => {
const t = searchParams.get('type')
if (t === 'troubleshooting' || t === 'procedural') {
if (t === 'troubleshooting' || t === 'procedural' || t === 'maintenance') {
setTypeFilter(t)
} else {
setTypeFilter('all')
@@ -253,14 +253,16 @@ export function TreeLibraryPage() {
<div className="mb-6 flex flex-col gap-4 sm:mb-8 sm:flex-row sm:items-start sm:justify-between">
<div>
<h1 className="text-2xl font-bold font-heading text-foreground sm:text-3xl">
{typeFilter === 'procedural' ? 'Projects' : typeFilter === 'troubleshooting' ? 'Troubleshooting Flows' : 'Flow Library'}
{typeFilter === 'procedural' ? 'Projects' : typeFilter === 'troubleshooting' ? 'Troubleshooting Flows' : typeFilter === 'maintenance' ? 'Maintenance Flows' : 'Flow Library'}
</h1>
<p className="mt-2 text-muted-foreground">
{typeFilter === 'procedural'
? 'Step-by-step projects and runbooks'
: typeFilter === 'troubleshooting'
? 'Branching decision flows for troubleshooting'
: 'Browse and start troubleshooting flows and projects'}
: typeFilter === 'maintenance'
? 'Scheduled maintenance procedures run across targets'
: 'Browse and start troubleshooting flows and projects'}
</p>
</div>
{canCreateTrees && (
@@ -326,7 +328,7 @@ export function TreeLibraryPage() {
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<div className="flex items-center gap-4">
<div className="flex rounded-lg border border-border p-0.5">
{(['all', 'troubleshooting', 'procedural'] as const).map((t) => (
{(['all', 'troubleshooting', 'procedural', 'maintenance'] as const).map((t) => (
<button
key={t}
onClick={() => setTypeFilter(t)}
@@ -337,7 +339,7 @@ export function TreeLibraryPage() {
: 'text-muted-foreground hover:text-foreground'
)}
>
{t === 'all' ? 'All' : t === 'troubleshooting' ? 'Troubleshooting' : 'Projects'}
{t === 'all' ? 'All' : t === 'troubleshooting' ? 'Troubleshooting' : t === 'procedural' ? 'Projects' : 'Maintenance'}
</button>
))}
</div>