feat(web): ontology-driven fleet treegrid, relations grouping, dev auto-config
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
ci / web (push) Has been cancelled
Desktop App / Build Linux (amd64) (push) Has been cancelled
Desktop App / Attach to Release (push) Has been cancelled

Knowledge Base / Fleet browsing:
- EntityTable renders as a treegrid (arbitrary depth, expand/collapse,
  ARIA row/level/expanded), grouped by parent-child relationships
  derived entirely from the live ontology graph (cardinality ->
  direction; typeDepth specificity for ties) rather than a hardcoded
  relationship list — see loadFleetGrouping in KnowledgeBase.svelte.
- Fold Services and Storage categories into Fleet (services/pools/
  volumes/datasets now nest under the compute entity or pool that
  provides/contains them instead of having their own browsing tabs).
- Drop `cluster` entities from Fleet browsing so a host's `located-at`
  (site) relationship wins the tree-parent slot without needing a
  hardcoded priority override — member-of simply has no valid target
  left to point at.
- Add a "show destroyed/inactive" Switch (default off) filtering on
  entity.state, replacing an always-on checkbox.

Entity detail panel:
- Split the Relations section into Outgoing/Incoming groups (relative
  to the viewed entity), and scope the section's count to edges
  actually incident to it rather than the whole depth-1 neighborhood.

Dev experience:
- Auto-fill the SPA's token from the dev server's own OIKOS_API_TOKEN
  (vite.config.ts define + main.ts, dev-only, only when unconfigured)
  so the "Connect to Oikos" prompt doesn't reappear on every reload.
- .claude/launch.json: autoPort, since port 5173 is often already
  claimed by another worktree's dev server.

Adds ui/checkbox and ui/switch (bits-ui primitives, following the
existing shadcn-svelte wrapper pattern) and fetchOntology()/
RelationshipTypeDef to api.ts. Also fixes a missing types.ts import
in api.ts (ChatEvent/MessageContent) that predates this branch.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-17 23:26:04 +02:00
parent 646373a676
commit 258b14dcbc
13 changed files with 403 additions and 67 deletions

View File

@@ -1,4 +1,7 @@
import { fetchWithAuth } from './config'
import type { ChatEvent, MessageContent } from './types'
export type { ChatEvent }
// Path prefixes only — NOT resolved URLs. fetchWithAuth resolves the actual
// origin (relative vs. configured apiUrl) fresh on every call via
@@ -221,13 +224,33 @@ export interface EntityType {
description?: string | null
}
export type RelationshipCardinality = 'one-to-one' | 'one-to-many' | 'many-to-one' | 'many-to-many'
export interface RelationshipTypeDef {
name: string
inverse?: string | null
source_type: string
target_type: string
cardinality: RelationshipCardinality
description?: string | null
}
export interface Ontology {
entityTypes: EntityType[]
relationshipTypes: RelationshipTypeDef[]
}
export async function fetchOntology(): Promise<Ontology> {
const res = await fetchWithAuth(`${API}/ontology`)
if (!res.ok) return { entityTypes: [], relationshipTypes: [] }
const data = await res.json()
return { entityTypes: data.entity_types ?? [], relationshipTypes: data.relationship_types ?? [] }
}
// The graph endpoint has no layer param, so callers build a type→layer map from
// this to scope the graph client-side (the entities table filters server-side).
export async function fetchEntityTypes(): Promise<EntityType[]> {
const res = await fetchWithAuth(`${API}/ontology`)
if (!res.ok) return []
const data = await res.json()
return data.entity_types ?? []
return (await fetchOntology()).entityTypes
}
export interface EventFilters {