11import { Billing } from "@opencode-ai/console-core/billing.js"
2- import { query , useParams , createAsync } from "@solidjs/router"
3- import { createMemo , For , Show } from "solid-js"
2+ import { createAsync , query , useParams } from "@solidjs/router"
3+ import { createMemo , For , Show , createEffect } from "solid-js"
44import { formatDateUTC , formatDateForTable } from "../common"
55import { withActor } from "~/context/auth.withActor"
6- import styles from "./usage-section.module.css"
6+ import "./usage-section.module.css"
7+ import { createStore } from "solid-js/store"
78
8- const getUsageInfo = query ( async ( workspaceID : string ) => {
9+ const PAGE_SIZE = 50
10+
11+ async function getUsageInfo ( workspaceID : string , page : number ) {
912 "use server"
1013 return withActor ( async ( ) => {
11- return await Billing . usages ( )
14+ return await Billing . usages ( page , PAGE_SIZE )
1215 } , workspaceID )
13- } , "usage.list" )
16+ }
17+
18+ const queryUsageInfo = query ( getUsageInfo , "usage.list" )
1419
1520export function UsageSection ( ) {
1621 const params = useParams ( )
17- // ORIGINAL CODE - COMMENTED OUT FOR TESTING
18- const usage = createAsync ( ( ) => getUsageInfo ( params . id ! ) )
22+ const usage = createAsync ( ( ) => queryUsageInfo ( params . id ! , 0 ) )
23+ const [ store , setStore ] = createStore ( { page : 0 , usage : [ ] as Awaited < ReturnType < typeof getUsageInfo > > } )
1924
20- // DUMMY DATA FOR TESTING
21- // const usage = () => [
22- // {
23- // timeCreated: new Date(Date.now() - 86400000 * 0).toISOString(), // Today
24- // model: "claude-3-5-sonnet-20241022",
25- // inputTokens: 1247,
26- // outputTokens: 423,
27- // cost: 125400000, // $1.254
28- // },
29- // {
30- // timeCreated: new Date(Date.now() - 86400000 * 0.5).toISOString(), // 12 hours ago
31- // model: "claude-3-haiku-20240307",
32- // inputTokens: 892,
33- // outputTokens: 156,
34- // cost: 23500000, // $0.235
35- // },
36- // {
37- // timeCreated: new Date(Date.now() - 86400000 * 1).toISOString(), // Yesterday
38- // model: "claude-3-5-sonnet-20241022",
39- // inputTokens: 2134,
40- // outputTokens: 687,
41- // cost: 234700000, // $2.347
42- // },
43- // {
44- // timeCreated: new Date(Date.now() - 86400000 * 1.3).toISOString(), // 1.3 days ago
45- // model: "gpt-4o-mini",
46- // inputTokens: 567,
47- // outputTokens: 234,
48- // cost: 8900000, // $0.089
49- // },
50- // {
51- // timeCreated: new Date(Date.now() - 86400000 * 2).toISOString(), // 2 days ago
52- // model: "claude-3-opus-20240229",
53- // inputTokens: 1893,
54- // outputTokens: 945,
55- // cost: 445600000, // $4.456
56- // },
57- // {
58- // timeCreated: new Date(Date.now() - 86400000 * 2.7).toISOString(), // 2.7 days ago
59- // model: "gpt-4o",
60- // inputTokens: 1456,
61- // outputTokens: 532,
62- // cost: 156800000, // $1.568
63- // },
64- // {
65- // timeCreated: new Date(Date.now() - 86400000 * 3).toISOString(), // 3 days ago
66- // model: "claude-3-haiku-20240307",
67- // inputTokens: 634,
68- // outputTokens: 89,
69- // cost: 12300000, // $0.123
70- // },
71- // {
72- // timeCreated: new Date(Date.now() - 86400000 * 4).toISOString(), // 4 days ago
73- // model: "claude-3-5-sonnet-20241022",
74- // inputTokens: 3245,
75- // outputTokens: 1123,
76- // cost: 387200000, // $3.872
77- // },
78- // ]
25+ createEffect ( ( ) => {
26+ setStore ( { usage : usage ( ) } )
27+ } , [ usage ] )
28+
29+ const hasResults = createMemo ( ( ) => store . usage . length > 0 )
30+ const canGoPrev = createMemo ( ( ) => store . page > 0 )
31+ const canGoNext = createMemo ( ( ) => store . usage . length === PAGE_SIZE )
32+
33+ const goPrev = async ( ) => {
34+ const usage = await getUsageInfo ( params . id ! , store . page - 1 )
35+ setStore ( {
36+ page : store . page - 1 ,
37+ usage,
38+ } )
39+ }
40+ const goNext = async ( ) => {
41+ const usage = await getUsageInfo ( params . id ! , store . page + 1 )
42+ setStore ( {
43+ page : store . page + 1 ,
44+ usage,
45+ } )
46+ }
7947
8048 return (
81- < section class = { styles . root } >
49+ < section >
8250 < div data-slot = "section-title" >
8351 < h2 > Usage History</ h2 >
8452 < p > Recent API usage and costs.</ p >
8553 </ div >
8654 < div data-slot = "usage-table" >
8755 < Show
88- when = { usage ( ) && usage ( ) ! . length > 0 }
56+ when = { hasResults ( ) }
8957 fallback = {
9058 < div data-component = "empty-state" >
9159 < p > Make your first API call to get started.</ p >
@@ -103,7 +71,7 @@ export function UsageSection() {
10371 </ tr >
10472 </ thead >
10573 < tbody >
106- < For each = { usage ( ) ! } >
74+ < For each = { store . usage } >
10775 { ( usage ) => {
10876 const date = createMemo ( ( ) => new Date ( usage . timeCreated ) )
10977 return (
@@ -121,6 +89,16 @@ export function UsageSection() {
12189 </ For >
12290 </ tbody >
12391 </ table >
92+ < Show when = { canGoPrev ( ) || canGoNext ( ) } >
93+ < div data-slot = "pagination" >
94+ < button disabled = { ! canGoPrev ( ) } onClick = { goPrev } >
95+ ←
96+ </ button >
97+ < button disabled = { ! canGoNext ( ) } onClick = { goNext } >
98+ →
99+ </ button >
100+ </ div >
101+ </ Show >
124102 </ Show >
125103 </ div >
126104 </ section >
0 commit comments