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

@@ -0,0 +1,36 @@
<script lang="ts">
import { Checkbox as CheckboxPrimitive } from 'bits-ui'
import CheckIcon from '@lucide/svelte/icons/check'
import MinusIcon from '@lucide/svelte/icons/minus'
import { cn } from '$lib/utils.js'
let {
ref = $bindable(null),
checked = $bindable(false),
indeterminate = $bindable(false),
class: className,
...restProps
}: CheckboxPrimitive.RootProps = $props()
</script>
<CheckboxPrimitive.Root
bind:ref
bind:checked
bind:indeterminate
data-slot="checkbox"
class={cn(
'peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-3 disabled:cursor-not-allowed disabled:opacity-50',
className
)}
{...restProps}
>
{#snippet children({ checked, indeterminate })}
<div data-slot="checkbox-indicator" class="flex items-center justify-center text-current transition-none">
{#if indeterminate}
<MinusIcon class="size-3.5" />
{:else if checked}
<CheckIcon class="size-3.5" />
{/if}
</div>
{/snippet}
</CheckboxPrimitive.Root>

View File

@@ -0,0 +1 @@
export { default as Checkbox } from './checkbox.svelte'

View File

@@ -0,0 +1 @@
export { default as Switch } from './switch.svelte'

View File

@@ -0,0 +1,27 @@
<script lang="ts">
import { Switch as SwitchPrimitive } from 'bits-ui'
import { cn } from '$lib/utils.js'
let {
ref = $bindable(null),
checked = $bindable(false),
class: className,
...restProps
}: SwitchPrimitive.RootProps = $props()
</script>
<SwitchPrimitive.Root
bind:ref
bind:checked
data-slot="switch"
class={cn(
'peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring/50 inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:ring-3 disabled:cursor-not-allowed disabled:opacity-50',
className
)}
{...restProps}
>
<SwitchPrimitive.Thumb
data-slot="switch-thumb"
class="bg-background pointer-events-none block size-4 rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0"
/>
</SwitchPrimitive.Root>