Overview
Demo mode lets developers and users explore the full Pastures UI without a running Engine backend. When enabled, all API calls return synthetic data with a simulated network delay.
Data Flow
isGlobalDemoMode()
├── true → load DEMO_* constants (with simulated delay)
└── false → isEngineConfigured()?
├── true → engineFetch() → safeJson()
└── false → show "Configure Engine" prompt
Two Demo Data Patterns
Pattern 1: engineFetch-based pages
Pages that call engineFetch() get demo data automatically via getDemoResponse() in lib/demoResponses.ts. Add a new case for your API path:
// lib/demoResponses.ts
export function getDemoResponse(path: string): any {
switch (path) {
// ... existing cases
case '/api/my-feature':
return {
items: [
{ id: 'demo-1', name: 'Demo item', status: 'healthy' },
{ id: 'demo-2', name: 'Another item', status: 'warning' },
],
};
}
}
Pattern 2: Inline fetch pages
Pages that use fetch directly (instead of engineFetch) define DEMO_* constants and check demo mode in onMounted:
const DEMO_METRICS = {
cpu: 42.5,
memory: 68.1,
pods: 127,
};
onMounted(async () => {
if (isGlobalDemoMode()) {
await new Promise((r) => setTimeout(r, 400));
metrics.value = DEMO_METRICS;
loading.value = false;
return;
}
// real API call
const res = await fetch(`${engineUrl}/api/metrics`, { headers });
metrics.value = await res.json();
loading.value = false;
});
Best Practices
Never silently fall back to demo data when the Engine is configured and expected to respond. If an API call fails in non-demo mode, surface the error to the user rather than quietly substituting synthetic data.
Realistic data
- Use plausible values: realistic cluster names (
prod-us-east-1), version strings (v1.28.4+rke2r1), timestamps, and counts.
- Include a mix of healthy and unhealthy states so the UI exercises all code paths.
- Match the exact response shape the Engine returns — demo data doubles as a contract test.
Simulated delay
Always add a short delay (300–500 ms) before resolving demo data. This exercises loading states and prevents UI flicker bugs from hiding behind instant responses.
await new Promise((r) => setTimeout(r, 400));
Naming conventions
- Prefix constants with
DEMO_ (e.g., DEMO_ADVISORIES, DEMO_CLUSTERS).
- Keep constants at the top of the
<script setup> block or in lib/demoResponses.ts.
Testing both paths
When developing a feature, toggle demo mode on and off in Settings to verify:
- The UI renders correctly with demo data.
- The UI renders correctly with live Engine data (or shows an appropriate error).
- Loading states display during the simulated delay.