ignore: cloud
This commit is contained in:
@@ -54,7 +54,10 @@
|
|||||||
|
|
||||||
a,
|
a,
|
||||||
button {
|
button {
|
||||||
|
appearance: none;
|
||||||
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
color: var(--color-text);
|
color: var(--color-text);
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
|
|||||||
@@ -1,7 +1,20 @@
|
|||||||
import "./workspace.css"
|
import "./workspace.css"
|
||||||
import { useAuthSession } from "~/context/auth.session"
|
import { useAuthSession } from "~/context/auth.session"
|
||||||
import { IconLogo } from "../component/icon"
|
import { IconLogo } from "../component/icon"
|
||||||
import { action, redirect, RouteSectionProps } from "@solidjs/router"
|
import { withActor } from "~/context/auth.withActor"
|
||||||
|
import "./workspace.css"
|
||||||
|
import { query, action, redirect, createAsync, RouteSectionProps } from "@solidjs/router"
|
||||||
|
import { User } from "@opencode/cloud-core/user.js"
|
||||||
|
import { Actor } from "@opencode/cloud-core/actor.js"
|
||||||
|
|
||||||
|
const getUserInfo = query(async () => {
|
||||||
|
"use server"
|
||||||
|
return withActor(async () => {
|
||||||
|
const actor = Actor.assert("user")
|
||||||
|
const user = await User.fromID(actor.properties.userID)
|
||||||
|
return { user }
|
||||||
|
})
|
||||||
|
}, "userInfo")
|
||||||
|
|
||||||
const logout = action(async () => {
|
const logout = action(async () => {
|
||||||
"use server"
|
"use server"
|
||||||
@@ -17,6 +30,7 @@ const logout = action(async () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
export default function WorkspaceLayout(props: RouteSectionProps) {
|
export default function WorkspaceLayout(props: RouteSectionProps) {
|
||||||
|
const userInfo = createAsync(() => getUserInfo())
|
||||||
return (
|
return (
|
||||||
<main data-page="workspace">
|
<main data-page="workspace">
|
||||||
<header data-component="workspace-header">
|
<header data-component="workspace-header">
|
||||||
@@ -26,7 +40,9 @@ export default function WorkspaceLayout(props: RouteSectionProps) {
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div data-slot="header-actions">
|
<div data-slot="header-actions">
|
||||||
<span>name@example.com</span>
|
{userInfo() &&
|
||||||
|
<span>{userInfo()!.user.email}</span>
|
||||||
|
}
|
||||||
<form action={logout} method="post">
|
<form action={logout} method="post">
|
||||||
<button type="submit" formaction={logout}>Logout</button>
|
<button type="submit" formaction={logout}>Logout</button>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -168,13 +168,13 @@
|
|||||||
[data-slot="api-keys-section"] {
|
[data-slot="api-keys-section"] {
|
||||||
[data-slot="create-form"] {
|
[data-slot="create-form"] {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
|
||||||
gap: var(--space-3);
|
gap: var(--space-3);
|
||||||
padding: var(--space-4);
|
padding: var(--space-4);
|
||||||
border: 1px solid var(--color-border);
|
border: 1px solid var(--color-border);
|
||||||
border-radius: var(--border-radius-sm);
|
border-radius: var(--border-radius-sm);
|
||||||
|
|
||||||
input {
|
input {
|
||||||
|
flex: 1;
|
||||||
padding: var(--space-2) var(--space-3);
|
padding: var(--space-2) var(--space-3);
|
||||||
border: 1px solid var(--color-border);
|
border: 1px solid var(--color-border);
|
||||||
border-radius: var(--border-radius-sm);
|
border-radius: var(--border-radius-sm);
|
||||||
@@ -196,7 +196,6 @@
|
|||||||
[data-slot="form-actions"] {
|
[data-slot="form-actions"] {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: var(--space-2);
|
gap: var(--space-2);
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,116 +63,8 @@ const createPortalUrl = action(async (returnUrl: string) => {
|
|||||||
return withActor(() => Billing.generatePortalUrl({ returnUrl }))
|
return withActor(() => Billing.generatePortalUrl({ returnUrl }))
|
||||||
}, "portalUrl")
|
}, "portalUrl")
|
||||||
|
|
||||||
const dummyUsageData = [
|
|
||||||
{
|
|
||||||
model: "claude-3-5-sonnet-20241022",
|
|
||||||
inputTokens: 1250,
|
|
||||||
outputTokens: 890,
|
|
||||||
reasoningTokens: 150,
|
|
||||||
cacheReadTokens: 0,
|
|
||||||
cacheWriteTokens: 45,
|
|
||||||
cost: 12340000,
|
|
||||||
timeCreated: new Date("2025-01-28T10:30:00Z"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
model: "claude-3-haiku-20240307",
|
|
||||||
inputTokens: 2100,
|
|
||||||
outputTokens: 450,
|
|
||||||
reasoningTokens: null,
|
|
||||||
cacheReadTokens: 120,
|
|
||||||
cacheWriteTokens: 0,
|
|
||||||
cost: 5670000,
|
|
||||||
timeCreated: new Date("2025-01-27T15:22:00Z"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
model: "claude-3-5-sonnet-20241022",
|
|
||||||
inputTokens: 850,
|
|
||||||
outputTokens: 1200,
|
|
||||||
reasoningTokens: 220,
|
|
||||||
cacheReadTokens: 30,
|
|
||||||
cacheWriteTokens: 15,
|
|
||||||
cost: 18990000,
|
|
||||||
timeCreated: new Date("2025-01-27T09:15:00Z"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
model: "claude-3-opus-20240229",
|
|
||||||
inputTokens: 3200,
|
|
||||||
outputTokens: 1800,
|
|
||||||
reasoningTokens: 400,
|
|
||||||
cacheReadTokens: 0,
|
|
||||||
cacheWriteTokens: 100,
|
|
||||||
cost: 45670000,
|
|
||||||
timeCreated: new Date("2025-01-26T14:45:00Z"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
model: "claude-3-haiku-20240307",
|
|
||||||
inputTokens: 650,
|
|
||||||
outputTokens: 280,
|
|
||||||
reasoningTokens: null,
|
|
||||||
cacheReadTokens: 200,
|
|
||||||
cacheWriteTokens: 0,
|
|
||||||
cost: 2340000,
|
|
||||||
timeCreated: new Date("2025-01-25T16:18:00Z"),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
const dummyPaymentData = [
|
|
||||||
{
|
|
||||||
id: "pay_1Ab2Cd3Ef4Gh5678",
|
|
||||||
amount: 2000000000,
|
|
||||||
timeCreated: new Date("2025-01-28T14:32:00Z"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "pay_9Ij8Kl7Mn6Op5432",
|
|
||||||
amount: 1000000000,
|
|
||||||
timeCreated: new Date("2025-01-25T09:18:00Z"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "pay_5Qr4St3Uv2Wx1098",
|
|
||||||
amount: 5000000000,
|
|
||||||
timeCreated: new Date("2025-01-20T16:45:00Z"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "pay_7Yz6Ab5Cd4Ef3210",
|
|
||||||
amount: 1500000000,
|
|
||||||
timeCreated: new Date("2025-01-15T11:22:00Z"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "pay_3Gh2Ij1Kl0Mn9876",
|
|
||||||
amount: 3000000000,
|
|
||||||
timeCreated: new Date("2025-01-10T13:55:00Z"),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
const dummyApiKeyData = [
|
|
||||||
{
|
|
||||||
id: "key_1Ab2Cd3Ef4Gh5678",
|
|
||||||
name: "Production API",
|
|
||||||
key: "oc_live_sk_1Ab2Cd3Ef4Gh567890123456789012345678901234567890",
|
|
||||||
timeCreated: new Date("2025-01-28T14:32:00Z"),
|
|
||||||
timeUsed: new Date("2025-01-29T09:15:00Z"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "key_9Ij8Kl7Mn6Op5432",
|
|
||||||
name: "Development Key",
|
|
||||||
key: "oc_test_sk_9Ij8Kl7Mn6Op543210987654321098765432109876543210",
|
|
||||||
timeCreated: new Date("2025-01-25T09:18:00Z"),
|
|
||||||
timeUsed: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "key_5Qr4St3Uv2Wx1098",
|
|
||||||
name: "CI/CD Pipeline",
|
|
||||||
key: "oc_live_sk_5Qr4St3Uv2Wx109876543210987654321098765432109876",
|
|
||||||
timeCreated: new Date("2025-01-20T16:45:00Z"),
|
|
||||||
timeUsed: new Date("2025-01-28T12:30:00Z"),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
export default function() {
|
export default function() {
|
||||||
const actor = createAsync(() => getActor())
|
const actor = createAsync(() => getActor())
|
||||||
onMount(() => {
|
|
||||||
console.log("MOUNTED", actor())
|
|
||||||
})
|
|
||||||
|
|
||||||
/////////////////
|
/////////////////
|
||||||
// Keys section
|
// Keys section
|
||||||
@@ -342,9 +234,8 @@ export default function() {
|
|||||||
</button>
|
</button>
|
||||||
</Show>
|
</Show>
|
||||||
<div data-slot="api-keys-table">
|
<div data-slot="api-keys-table">
|
||||||
{/* when={keys()?.length */}
|
|
||||||
<Show
|
<Show
|
||||||
when={dummyApiKeyData.length > 0}
|
when={keys()?.length}
|
||||||
fallback={
|
fallback={
|
||||||
<div data-slot="empty-state">
|
<div data-slot="empty-state">
|
||||||
<p>Create an opencode Gateway API key</p>
|
<p>Create an opencode Gateway API key</p>
|
||||||
@@ -361,8 +252,7 @@ export default function() {
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<For each={dummyApiKeyData}>
|
<For each={keys()!}>
|
||||||
{/* Real data: keys() */}
|
|
||||||
{(key) => (
|
{(key) => (
|
||||||
<tr>
|
<tr>
|
||||||
<td data-slot="key-name">{key.name}</td>
|
<td data-slot="key-name">{key.name}</td>
|
||||||
@@ -424,45 +314,6 @@ export default function() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Payments Section */}
|
|
||||||
<Show when={dummyPaymentData.length > 0}>
|
|
||||||
{/* Real data condition: billingInfo() && billingInfo()!.payments.length > 0 */}
|
|
||||||
<section data-slot="payments-section">
|
|
||||||
<div data-slot="section-title">
|
|
||||||
<h2>Payments History</h2>
|
|
||||||
<p>Recent payment transactions.</p>
|
|
||||||
</div>
|
|
||||||
<div data-slot="payments-table">
|
|
||||||
<table data-slot="payments-table-element">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Date</th>
|
|
||||||
<th>Payment ID</th>
|
|
||||||
<th>Amount</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<For each={dummyPaymentData}>
|
|
||||||
{/* Real data: billingInfo()?.payments */}
|
|
||||||
{(payment) => {
|
|
||||||
const date = new Date(payment.timeCreated)
|
|
||||||
return (
|
|
||||||
<tr>
|
|
||||||
<td data-slot="payment-date" title={formatDateUTC(date)}>
|
|
||||||
{formatDateForTable(date)}
|
|
||||||
</td>
|
|
||||||
<td data-slot="payment-id">{payment.id}</td>
|
|
||||||
<td data-slot="payment-amount">${((payment.amount ?? 0) / 100000000).toFixed(2)}</td>
|
|
||||||
</tr>
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
</For>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</Show>
|
|
||||||
|
|
||||||
{/* Usage Section */}
|
{/* Usage Section */}
|
||||||
<section data-slot="usage-section">
|
<section data-slot="usage-section">
|
||||||
<div data-slot="section-title">
|
<div data-slot="section-title">
|
||||||
@@ -471,7 +322,7 @@ export default function() {
|
|||||||
</div>
|
</div>
|
||||||
<div data-slot="usage-table">
|
<div data-slot="usage-table">
|
||||||
<Show
|
<Show
|
||||||
when={dummyUsageData.length > 0}
|
when={billingInfo() && billingInfo()!.usage.length > 0}
|
||||||
fallback={
|
fallback={
|
||||||
<div data-slot="empty-state">
|
<div data-slot="empty-state">
|
||||||
<p>Make your first API call to get started.</p>
|
<p>Make your first API call to get started.</p>
|
||||||
@@ -488,7 +339,7 @@ export default function() {
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<For each={dummyUsageData}>
|
<For each={billingInfo()!.usage}>
|
||||||
{(usage) => {
|
{(usage) => {
|
||||||
const totalTokens = usage.inputTokens + usage.outputTokens + (usage.reasoningTokens || 0)
|
const totalTokens = usage.inputTokens + usage.outputTokens + (usage.reasoningTokens || 0)
|
||||||
const date = new Date(usage.timeCreated)
|
const date = new Date(usage.timeCreated)
|
||||||
@@ -509,6 +360,44 @@ export default function() {
|
|||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
{/* Payments Section */}
|
||||||
|
<Show when={billingInfo() && billingInfo()!.payments.length > 0}>
|
||||||
|
<section data-slot="payments-section">
|
||||||
|
<div data-slot="section-title">
|
||||||
|
<h2>Payments History</h2>
|
||||||
|
<p>Recent payment transactions.</p>
|
||||||
|
</div>
|
||||||
|
<div data-slot="payments-table">
|
||||||
|
<table data-slot="payments-table-element">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Date</th>
|
||||||
|
<th>Payment ID</th>
|
||||||
|
<th>Amount</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<For each={billingInfo()!.payments}>
|
||||||
|
{(payment) => {
|
||||||
|
const date = new Date(payment.timeCreated)
|
||||||
|
return (
|
||||||
|
<tr>
|
||||||
|
<td data-slot="payment-date" title={formatDateUTC(date)}>
|
||||||
|
{formatDateForTable(date)}
|
||||||
|
</td>
|
||||||
|
<td data-slot="payment-id">{payment.id}</td>
|
||||||
|
<td data-slot="payment-amount">${((payment.amount ?? 0) / 100000000).toFixed(2)}</td>
|
||||||
|
</tr>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</For>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</Show>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user