diff options
| author | Jay V <[email protected]> | 2025-08-30 15:28:35 -0400 |
|---|---|---|
| committer | Jay V <[email protected]> | 2025-08-30 15:28:35 -0400 |
| commit | d3bbaa141ca74853d5f4c9f2a13575adedf824d8 (patch) | |
| tree | 083bde744bf5ea23f01f2d4b18c8bbffcd4e9358 /cloud | |
| parent | 8714f235090ca7977662c36bdff2413bbe200943 (diff) | |
| download | opencode-d3bbaa141ca74853d5f4c9f2a13575adedf824d8.tar.gz opencode-d3bbaa141ca74853d5f4c9f2a13575adedf824d8.zip | |
ignore: cloud
Diffstat (limited to 'cloud')
| -rw-r--r-- | cloud/app/src/routes/workspace.css | 3 | ||||
| -rw-r--r-- | cloud/app/src/routes/workspace.tsx | 20 | ||||
| -rw-r--r-- | cloud/app/src/routes/workspace/[id].css | 3 | ||||
| -rw-r--r-- | cloud/app/src/routes/workspace/[id].tsx | 195 |
4 files changed, 64 insertions, 157 deletions
diff --git a/cloud/app/src/routes/workspace.css b/cloud/app/src/routes/workspace.css index e18b410ee..e378ef461 100644 --- a/cloud/app/src/routes/workspace.css +++ b/cloud/app/src/routes/workspace.css @@ -54,7 +54,10 @@ a, button { + appearance: none; + background: none; border: none; + cursor: pointer; padding: 0; color: var(--color-text); text-decoration: underline; diff --git a/cloud/app/src/routes/workspace.tsx b/cloud/app/src/routes/workspace.tsx index 6876ae962..f75af8e74 100644 --- a/cloud/app/src/routes/workspace.tsx +++ b/cloud/app/src/routes/workspace.tsx @@ -1,7 +1,20 @@ import "./workspace.css" import { useAuthSession } from "~/context/auth.session" 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 () => { "use server" @@ -17,6 +30,7 @@ const logout = action(async () => { }) export default function WorkspaceLayout(props: RouteSectionProps) { + const userInfo = createAsync(() => getUserInfo()) return ( <main data-page="workspace"> <header data-component="workspace-header"> @@ -26,7 +40,9 @@ export default function WorkspaceLayout(props: RouteSectionProps) { </a> </div> <div data-slot="header-actions"> - <span>[email protected]</span> + {userInfo() && + <span>{userInfo()!.user.email}</span> + } <form action={logout} method="post"> <button type="submit" formaction={logout}>Logout</button> </form> diff --git a/cloud/app/src/routes/workspace/[id].css b/cloud/app/src/routes/workspace/[id].css index d29f5af32..651cae627 100644 --- a/cloud/app/src/routes/workspace/[id].css +++ b/cloud/app/src/routes/workspace/[id].css @@ -168,13 +168,13 @@ [data-slot="api-keys-section"] { [data-slot="create-form"] { display: flex; - flex-direction: column; gap: var(--space-3); padding: var(--space-4); border: 1px solid var(--color-border); border-radius: var(--border-radius-sm); input { + flex: 1; padding: var(--space-2) var(--space-3); border: 1px solid var(--color-border); border-radius: var(--border-radius-sm); @@ -196,7 +196,6 @@ [data-slot="form-actions"] { display: flex; gap: var(--space-2); - justify-content: flex-end; } } diff --git a/cloud/app/src/routes/workspace/[id].tsx b/cloud/app/src/routes/workspace/[id].tsx index 70f1a7cdb..a03811c17 100644 --- a/cloud/app/src/routes/workspace/[id].tsx +++ b/cloud/app/src/routes/workspace/[id].tsx @@ -63,116 +63,8 @@ const createPortalUrl = action(async (returnUrl: string) => { return withActor(() => Billing.generatePortalUrl({ returnUrl })) }, "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() { const actor = createAsync(() => getActor()) - onMount(() => { - console.log("MOUNTED", actor()) - }) ///////////////// // Keys section @@ -342,9 +234,8 @@ export default function() { </button> </Show> <div data-slot="api-keys-table"> - {/* when={keys()?.length */} <Show - when={dummyApiKeyData.length > 0} + when={keys()?.length} fallback={ <div data-slot="empty-state"> <p>Create an opencode Gateway API key</p> @@ -361,8 +252,7 @@ export default function() { </tr> </thead> <tbody> - <For each={dummyApiKeyData}> - {/* Real data: keys() */} + <For each={keys()!}> {(key) => ( <tr> <td data-slot="key-name">{key.name}</td> @@ -424,45 +314,6 @@ export default function() { </div> </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 */} <section data-slot="usage-section"> <div data-slot="section-title"> @@ -471,7 +322,7 @@ export default function() { </div> <div data-slot="usage-table"> <Show - when={dummyUsageData.length > 0} + when={billingInfo() && billingInfo()!.usage.length > 0} fallback={ <div data-slot="empty-state"> <p>Make your first API call to get started.</p> @@ -488,7 +339,7 @@ export default function() { </tr> </thead> <tbody> - <For each={dummyUsageData}> + <For each={billingInfo()!.usage}> {(usage) => { const totalTokens = usage.inputTokens + usage.outputTokens + (usage.reasoningTokens || 0) const date = new Date(usage.timeCreated) @@ -509,6 +360,44 @@ export default function() { </Show> </div> </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> ) |
