// Aggregate views: API Keys overview, Metrics, Skills library, Billing function KeysView({ instances, onOpenInstance }) { const openaiCount = instances.filter(i => i.apiProvider === "openai").length; const anthropicCount = instances.filter(i => i.apiProvider === "anthropic").length; return (

API keys

Per-instance BYO keys · {instances.length} instances · {openaiCount} OpenAI · {anthropicCount} Anthropic

Keys by instance

{instances.map((inst) => { const sample = inst.apiProvider === "openai" ? "sk-proj-" + inst.id.replace(/-/g,"").slice(0, 6) + "•••••••••••" : "sk-ant-api03-" + inst.id.replace(/-/g,"").slice(0, 6) + "•••••••"; const usage = inst.cost; const pct = Math.min(95, Math.round(usage / 75 * 100)); const warn = pct > 85; return ( onOpenInstance(inst.id)}> ); })}
Instance Provider Key Status Month usage Last used
{inst.name}
{inst.apiProvider === "openai" ? "OpenAI" : "Anthropic"} {sample} {warn ? Quota 92% : Healthy} {fmtEur(usage)} {Math.floor(Math.random() * 59) + 1}m ago
); } function MetricsView({ instances }) { const totalIn = instances.reduce((a,i)=>a+i.tokensIn,0); const totalOut = instances.reduce((a,i)=>a+i.tokensOut,0); const totalCost = instances.reduce((a,i)=>a+i.cost,0); const topByCost = [...instances].sort((a,b)=>b.cost-a.cost).slice(0,6); const topBySkills = window.APP_DATA.SKILLS.map((s) => ({ skill: s, count: instances.filter(i=>i.skills.includes(s)).length, invocations: Math.floor(Math.random() * 4000) + 200, })).sort((a,b)=>b.invocations-a.invocations); const days = Array.from({ length: 30 }, (_, i) => i); const seriesIn = days.map((d) => 300_000 + Math.sin(d / 3) * 60_000 + Math.random() * 40_000 + d * 4_000); const seriesOut = days.map((d) => 80_000 + Math.cos(d / 4) * 18_000 + Math.random() * 12_000 + d * 1_400); const dayLabels = days.map((d) => { const dt = new Date(2026, 2, 22 + d); return `${dt.getDate()}.${dt.getMonth() + 1}`; }); return (

Metrics

Token usage, cost, skill breakdown across all instances

{["24h","7d","30d","90d"].map((r,i) => (
{r}
))}

Token consumption

· 30d, all instances · input + output

Top instances by cost

· this month
{topByCost.map((inst) => { const pct = (inst.cost / topByCost[0].cost) * 100; return (
{inst.name}
{fmtEur(inst.cost)}
); })}

Skills usage

· invocations, 30d
s.invocations)} labels={topBySkills.slice(0,10).map(s=>s.skill.replace("oprt-",""))} height={200} color="var(--violet)" />

Cost breakdown

· by instance
{instances.map((inst) => ( ))}
Instance Provider Input Output Messages Cost € / 1k msgs
{inst.name}
{inst.apiProvider} {fmtNum(inst.tokensIn)} {fmtNum(inst.tokensOut)} {fmtNum(inst.messages)} {fmtEur(inst.cost)} {fmtEur(inst.cost / Math.max(1, inst.messages) * 1000)}
); } function SkillsView({ instances }) { const allSkills = window.APP_DATA.SKILLS; const byCategory = { "Google": ["oprt-gmail", "oprt-calendar", "oprt-google-docs", "oprt-google-sheets", "oprt-google-drive"], "Microsoft": ["oprt-microsoft-auth", "oprt-outlook", "oprt-outlook-cal", "oprt-onedrive", "oprt-sharepoint", "oprt-teams"], "CRM & Workspace": ["oprt-hubspot", "oprt-notion", "oprt-connect"], "Customer lifecycle": ["oprt-onboarding", "oprt-transcripts", "oprt-security"], "Finance": ["oprt-qonto"], }; return (

Skills library

{allSkills.length} installable skills · assign to any instance from the launch form or detail page

{Object.entries(byCategory).map(([cat, skills]) => (

{cat}

· {skills.length} skills
{skills.map((s) => { const count = instances.filter(i => i.skills.includes(s)).length; const pct = Math.round((count / instances.length) * 100); const inv = Math.floor(Math.random() * 4800) + 120; return (
{s} v1.4
{s.includes("gmail") ? "Read, search, draft & send email threads." : s.includes("calendar") ? "Schedule, move and cancel events." : s.includes("hubspot") ? "Sync contacts, deals, pipelines." : s.includes("notion") ? "Read/write pages, databases, tasks." : s.includes("docs") ? "Compose and edit documents." : s.includes("sheets") ? "Query, update, append rows." : s.includes("drive") ? "Browse, search, upload files." : s.includes("outlook") ? "Microsoft 365 email." : s.includes("teams") ? "Send messages, read channels." : s.includes("qonto") ? "Read transactions, tag invoices." : s.includes("onboarding") ? "Guided first-run flow for new users." : s.includes("transcripts") ? "Generate and store call transcripts." : s.includes("security") ? "PII redaction, audit logging." : "Integration skill for connected workflows."}
Used by {count}/{instances.length} instances {inv} inv / 30d
); })}
))}
); } function BillingView({ instances }) { const total = instances.reduce((a,i)=>a+i.cost,0); const margin = instances.reduce((a,i)=> a + (i.plan === "Trial" ? 0 : i.plan === "Starter" ? 49 : i.plan === "Growth" ? 149 : 499), 0); return (

Billing

Customer invoices, subscriptions and model cost pass-through

Customer accounts

{instances.map((inst) => { const fee = inst.plan === "Trial" ? 0 : inst.plan === "Starter" ? 49 : inst.plan === "Growth" ? 149 : 499; return ( ); })}
Customer Plan Status Plan fee Model cost MTD Next invoice
{inst.name}
{inst.email}
{inst.plan} €{fee.toFixed(2)} {fmtEur(inst.cost)} 2026-05-01

Recent invoices

{[ { n: "INV-2941", c: "Kranich Legal", a: 648.60, d: "2026-04-01", s: "Paid" }, { n: "INV-2940", c: "Heiztec AG", a: 231.14, d: "2026-04-01", s: "Paid" }, { n: "INV-2939", c: "Mustermann GmbH", a: 197.72, d: "2026-04-01", s: "Paid" }, { n: "INV-2938", c: "Nordflow Logistics", a: 185.40, d: "2026-04-01", s: "Overdue" }, { n: "INV-2937", c: "Sonnenhof Hotels", a: 173.90, d: "2026-04-01", s: "Paid" }, { n: "INV-2936", c: "Arktis Manufactur", a: 190.80, d: "2026-04-01", s: "Open" }, ].map((r) => ( ))}
#CustomerAmountDateStatus
{r.n} {r.c} €{r.a.toFixed(2)} {r.d} {r.s === "Paid" ? Paid : r.s === "Overdue" ? Overdue : Open}
); } window.KeysView = KeysView; window.MetricsView = MetricsView; window.SkillsView = SkillsView; window.BillingView = BillingView;