feat(frontend): add Phase 3 UI components for observability

Components created:
- ValidationWarningsAlert: Display validation warnings with collapsible list
- StructuredErrorDisplay: Parse and display HTTP 502 errors as bullet points
- AutoFixBadge: Show automatically applied fixes
- ReasoningChainViewer: Collapsible panel for LLM thinking process
- MetadataDebugPanel: Collapsible debug info (model, duration, token metrics)

CSS changes:
- Add .editorial-alert--warning and .editorial-alert--info variants

Integration:
- Update routines/suggest page to show warnings, auto-fixes, reasoning, and metadata
- Update products/suggest page with same observability components
- Replace plain error divs with StructuredErrorDisplay for better UX

All components follow design system and pass svelte-check with 0 errors
This commit is contained in:
Piotr Oleszczyk 2026-03-06 15:53:46 +01:00
parent 3c3248c2ea
commit 5d3f876bec
8 changed files with 310 additions and 3 deletions

View file

@ -0,0 +1,48 @@
<script lang="ts">
import { XCircle } from 'lucide-svelte';
interface Props {
error: string;
}
let { error }: Props = $props();
// Parse semicolon-separated errors from backend validation failures
const errors = $derived(
error.includes(';')
? error
.split(';')
.map((e) => e.trim())
.filter((e) => e.length > 0)
: [error]
);
// Extract prefix if present (e.g., "Generated routine failed safety validation: ")
const hasPrefix = $derived(errors.length === 1 && errors[0].includes(': '));
const prefix = $derived(
hasPrefix ? errors[0].substring(0, errors[0].indexOf(': ') + 1) : ''
);
const cleanedErrors = $derived(
hasPrefix && prefix ? [errors[0].substring(prefix.length)] : errors
);
</script>
<div class="editorial-alert editorial-alert--error">
<div class="flex items-start gap-2">
<XCircle class="size-5 shrink-0 mt-0.5" />
<div class="flex-1">
{#if prefix}
<p class="font-medium mb-2">{prefix.replace(':', '')}</p>
{/if}
{#if cleanedErrors.length === 1}
<p>{cleanedErrors[0]}</p>
{:else}
<ul class="list-disc list-inside space-y-1">
{#each cleanedErrors as err}
<li>{err}</li>
{/each}
</ul>
{/if}
</div>
</div>
</div>