zen: add usage section

This commit is contained in:
Frank
2026-03-11 00:39:56 -04:00
parent fac23a1afc
commit ed3bb3ea8f
24 changed files with 45 additions and 7 deletions

View File

@@ -411,6 +411,7 @@ export const dict = {
"black.subscribe.success.chargeNotice": "سيتم خصم المبلغ من بطاقتك عند تفعيل اشتراكك", "black.subscribe.success.chargeNotice": "سيتم خصم المبلغ من بطاقتك عند تفعيل اشتراكك",
"workspace.nav.zen": "Zen", "workspace.nav.zen": "Zen",
"workspace.nav.usage": "الاستخدام",
"workspace.nav.apiKeys": "مفاتيح API", "workspace.nav.apiKeys": "مفاتيح API",
"workspace.nav.members": "الأعضاء", "workspace.nav.members": "الأعضاء",
"workspace.nav.billing": "الفوترة", "workspace.nav.billing": "الفوترة",

View File

@@ -418,6 +418,7 @@ export const dict = {
"black.subscribe.success.chargeNotice": "Seu cartão será cobrado quando sua assinatura for ativada", "black.subscribe.success.chargeNotice": "Seu cartão será cobrado quando sua assinatura for ativada",
"workspace.nav.zen": "Zen", "workspace.nav.zen": "Zen",
"workspace.nav.usage": "Uso",
"workspace.nav.apiKeys": "Chaves de API", "workspace.nav.apiKeys": "Chaves de API",
"workspace.nav.members": "Membros", "workspace.nav.members": "Membros",
"workspace.nav.billing": "Faturamento", "workspace.nav.billing": "Faturamento",

View File

@@ -414,6 +414,7 @@ export const dict = {
"black.subscribe.success.chargeNotice": "Dit kort vil blive debiteret, når dit abonnement er aktiveret", "black.subscribe.success.chargeNotice": "Dit kort vil blive debiteret, når dit abonnement er aktiveret",
"workspace.nav.zen": "Zen", "workspace.nav.zen": "Zen",
"workspace.nav.usage": "Brug",
"workspace.nav.apiKeys": "API-nøgler", "workspace.nav.apiKeys": "API-nøgler",
"workspace.nav.members": "Medlemmer", "workspace.nav.members": "Medlemmer",
"workspace.nav.billing": "Fakturering", "workspace.nav.billing": "Fakturering",

View File

@@ -417,6 +417,7 @@ export const dict = {
"black.subscribe.success.chargeNotice": "Deine Karte wird belastet, sobald dein Abonnement aktiviert ist", "black.subscribe.success.chargeNotice": "Deine Karte wird belastet, sobald dein Abonnement aktiviert ist",
"workspace.nav.zen": "Zen", "workspace.nav.zen": "Zen",
"workspace.nav.usage": "Nutzung",
"workspace.nav.apiKeys": "API Keys", "workspace.nav.apiKeys": "API Keys",
"workspace.nav.members": "Mitglieder", "workspace.nav.members": "Mitglieder",
"workspace.nav.billing": "Abrechnung", "workspace.nav.billing": "Abrechnung",

View File

@@ -411,6 +411,7 @@ export const dict = {
"black.subscribe.success.chargeNotice": "Your card will be charged when your subscription is activated", "black.subscribe.success.chargeNotice": "Your card will be charged when your subscription is activated",
"workspace.nav.zen": "Zen", "workspace.nav.zen": "Zen",
"workspace.nav.usage": "Usage",
"workspace.nav.apiKeys": "API Keys", "workspace.nav.apiKeys": "API Keys",
"workspace.nav.members": "Members", "workspace.nav.members": "Members",
"workspace.nav.billing": "Billing", "workspace.nav.billing": "Billing",

View File

@@ -419,6 +419,7 @@ export const dict = {
"black.subscribe.success.chargeNotice": "Tu tarjeta se cargará cuando tu suscripción se active", "black.subscribe.success.chargeNotice": "Tu tarjeta se cargará cuando tu suscripción se active",
"workspace.nav.zen": "Zen", "workspace.nav.zen": "Zen",
"workspace.nav.usage": "Uso",
"workspace.nav.apiKeys": "Claves API", "workspace.nav.apiKeys": "Claves API",
"workspace.nav.members": "Miembros", "workspace.nav.members": "Miembros",
"workspace.nav.billing": "Facturación", "workspace.nav.billing": "Facturación",

View File

@@ -419,6 +419,7 @@ export const dict = {
"black.subscribe.success.chargeNotice": "Votre carte sera débitée lorsque votre abonnement sera activé", "black.subscribe.success.chargeNotice": "Votre carte sera débitée lorsque votre abonnement sera activé",
"workspace.nav.zen": "Zen", "workspace.nav.zen": "Zen",
"workspace.nav.usage": "Utilisation",
"workspace.nav.apiKeys": "Clés API", "workspace.nav.apiKeys": "Clés API",
"workspace.nav.members": "Membres", "workspace.nav.members": "Membres",
"workspace.nav.billing": "Facturation", "workspace.nav.billing": "Facturation",

View File

@@ -417,6 +417,7 @@ export const dict = {
"black.subscribe.success.chargeNotice": "La tua carta verrà addebitata quando il tuo abbonamento sarà attivato", "black.subscribe.success.chargeNotice": "La tua carta verrà addebitata quando il tuo abbonamento sarà attivato",
"workspace.nav.zen": "Zen", "workspace.nav.zen": "Zen",
"workspace.nav.usage": "Utilizzo",
"workspace.nav.apiKeys": "Chiavi API", "workspace.nav.apiKeys": "Chiavi API",
"workspace.nav.members": "Membri", "workspace.nav.members": "Membri",
"workspace.nav.billing": "Fatturazione", "workspace.nav.billing": "Fatturazione",

View File

@@ -416,6 +416,7 @@ export const dict = {
"black.subscribe.success.chargeNotice": "サブスクリプションが有効化された時点でカードに請求されます", "black.subscribe.success.chargeNotice": "サブスクリプションが有効化された時点でカードに請求されます",
"workspace.nav.zen": "Zen", "workspace.nav.zen": "Zen",
"workspace.nav.usage": "利用",
"workspace.nav.apiKeys": "APIキー", "workspace.nav.apiKeys": "APIキー",
"workspace.nav.members": "メンバー", "workspace.nav.members": "メンバー",
"workspace.nav.billing": "請求", "workspace.nav.billing": "請求",

View File

@@ -410,6 +410,7 @@ export const dict = {
"black.subscribe.success.chargeNotice": "구독이 활성화되면 카드에 청구됩니다", "black.subscribe.success.chargeNotice": "구독이 활성화되면 카드에 청구됩니다",
"workspace.nav.zen": "Zen", "workspace.nav.zen": "Zen",
"workspace.nav.usage": "사용량",
"workspace.nav.apiKeys": "API 키", "workspace.nav.apiKeys": "API 키",
"workspace.nav.members": "멤버", "workspace.nav.members": "멤버",
"workspace.nav.billing": "결제", "workspace.nav.billing": "결제",

View File

@@ -415,6 +415,7 @@ export const dict = {
"black.subscribe.success.chargeNotice": "Kortet ditt vil bli belastet når abonnementet aktiveres", "black.subscribe.success.chargeNotice": "Kortet ditt vil bli belastet når abonnementet aktiveres",
"workspace.nav.zen": "Zen", "workspace.nav.zen": "Zen",
"workspace.nav.usage": "Bruk",
"workspace.nav.apiKeys": "API-nøkler", "workspace.nav.apiKeys": "API-nøkler",
"workspace.nav.members": "Medlemmer", "workspace.nav.members": "Medlemmer",
"workspace.nav.billing": "Fakturering", "workspace.nav.billing": "Fakturering",

View File

@@ -416,6 +416,7 @@ export const dict = {
"black.subscribe.success.chargeNotice": "Twoja karta zostanie obciążona po aktywacji subskrypcji", "black.subscribe.success.chargeNotice": "Twoja karta zostanie obciążona po aktywacji subskrypcji",
"workspace.nav.zen": "Zen", "workspace.nav.zen": "Zen",
"workspace.nav.usage": "Użycie",
"workspace.nav.apiKeys": "Klucze API", "workspace.nav.apiKeys": "Klucze API",
"workspace.nav.members": "Członkowie", "workspace.nav.members": "Członkowie",
"workspace.nav.billing": "Rozliczenia", "workspace.nav.billing": "Rozliczenia",

View File

@@ -421,6 +421,7 @@ export const dict = {
"black.subscribe.success.chargeNotice": "С вашей карты будет списана оплата при активации подписки", "black.subscribe.success.chargeNotice": "С вашей карты будет списана оплата при активации подписки",
"workspace.nav.zen": "Zen", "workspace.nav.zen": "Zen",
"workspace.nav.usage": "Использование",
"workspace.nav.apiKeys": "API Ключи", "workspace.nav.apiKeys": "API Ключи",
"workspace.nav.members": "Участники", "workspace.nav.members": "Участники",
"workspace.nav.billing": "Оплата", "workspace.nav.billing": "Оплата",

View File

@@ -413,6 +413,7 @@ export const dict = {
"black.subscribe.success.chargeNotice": "บัตรของคุณจะถูกเรียกเก็บเงินเมื่อการสมัครสมาชิกของคุณถูกเปิดใช้งาน", "black.subscribe.success.chargeNotice": "บัตรของคุณจะถูกเรียกเก็บเงินเมื่อการสมัครสมาชิกของคุณถูกเปิดใช้งาน",
"workspace.nav.zen": "Zen", "workspace.nav.zen": "Zen",
"workspace.nav.usage": "การใช้งาน",
"workspace.nav.apiKeys": "API Keys", "workspace.nav.apiKeys": "API Keys",
"workspace.nav.members": "สมาชิก", "workspace.nav.members": "สมาชิก",
"workspace.nav.billing": "การเรียกเก็บเงิน", "workspace.nav.billing": "การเรียกเก็บเงิน",

View File

@@ -418,6 +418,7 @@ export const dict = {
"black.subscribe.success.chargeNotice": "Aboneliğiniz aktive edildiğinde kartınızdan ödeme alınacaktır", "black.subscribe.success.chargeNotice": "Aboneliğiniz aktive edildiğinde kartınızdan ödeme alınacaktır",
"workspace.nav.zen": "Zen", "workspace.nav.zen": "Zen",
"workspace.nav.usage": "Kullanım",
"workspace.nav.apiKeys": "API Anahtarları", "workspace.nav.apiKeys": "API Anahtarları",
"workspace.nav.members": "Üyeler", "workspace.nav.members": "Üyeler",
"workspace.nav.billing": "Faturalandırma", "workspace.nav.billing": "Faturalandırma",

View File

@@ -396,6 +396,7 @@ export const dict = {
"black.subscribe.success.chargeNotice": "您的卡将在订阅激活时扣费", "black.subscribe.success.chargeNotice": "您的卡将在订阅激活时扣费",
"workspace.nav.zen": "Zen", "workspace.nav.zen": "Zen",
"workspace.nav.usage": "使用量",
"workspace.nav.apiKeys": "API 密钥", "workspace.nav.apiKeys": "API 密钥",
"workspace.nav.members": "成员", "workspace.nav.members": "成员",
"workspace.nav.billing": "计费", "workspace.nav.billing": "计费",

View File

@@ -397,6 +397,7 @@ export const dict = {
"black.subscribe.success.chargeNotice": "你的卡片將在訂閱啟用時扣款", "black.subscribe.success.chargeNotice": "你的卡片將在訂閱啟用時扣款",
"workspace.nav.zen": "Zen", "workspace.nav.zen": "Zen",
"workspace.nav.usage": "使用量",
"workspace.nav.apiKeys": "API 金鑰", "workspace.nav.apiKeys": "API 金鑰",
"workspace.nav.members": "成員", "workspace.nav.members": "成員",
"workspace.nav.billing": "帳務", "workspace.nav.billing": "帳務",

View File

@@ -19,6 +19,9 @@ export default function WorkspaceLayout(props: RouteSectionProps) {
<A href={`/workspace/${params.id}`} end activeClass="active" data-nav-button> <A href={`/workspace/${params.id}`} end activeClass="active" data-nav-button>
{i18n.t("workspace.nav.zen")} {i18n.t("workspace.nav.zen")}
</A> </A>
<A href={`/workspace/${params.id}/usage`} activeClass="active" data-nav-button>
{i18n.t("workspace.nav.usage")}
</A>
<A href={`/workspace/${params.id}/keys`} activeClass="active" data-nav-button> <A href={`/workspace/${params.id}/keys`} activeClass="active" data-nav-button>
{i18n.t("workspace.nav.apiKeys")} {i18n.t("workspace.nav.apiKeys")}
</A> </A>
@@ -41,6 +44,9 @@ export default function WorkspaceLayout(props: RouteSectionProps) {
<A href={`/workspace/${params.id}`} end activeClass="active" data-nav-button> <A href={`/workspace/${params.id}`} end activeClass="active" data-nav-button>
{i18n.t("workspace.nav.zen")} {i18n.t("workspace.nav.zen")}
</A> </A>
<A href={`/workspace/${params.id}/usage`} activeClass="active" data-nav-button>
{i18n.t("workspace.nav.usage")}
</A>
<A href={`/workspace/${params.id}/keys`} activeClass="active" data-nav-button> <A href={`/workspace/${params.id}/keys`} activeClass="active" data-nav-button>
{i18n.t("workspace.nav.apiKeys")} {i18n.t("workspace.nav.apiKeys")}
</A> </A>

View File

@@ -2,10 +2,8 @@ import { Match, Show, Switch, createMemo } from "solid-js"
import { createStore } from "solid-js/store" import { createStore } from "solid-js/store"
import { createAsync, useParams, useAction, useSubmission } from "@solidjs/router" import { createAsync, useParams, useAction, useSubmission } from "@solidjs/router"
import { NewUserSection } from "./new-user-section" import { NewUserSection } from "./new-user-section"
import { UsageSection } from "./usage-section"
import { ModelSection } from "./model-section" import { ModelSection } from "./model-section"
import { ProviderSection } from "./provider-section" import { ProviderSection } from "./provider-section"
import { GraphSection } from "./graph-section"
import { IconLogo } from "~/component/icon" import { IconLogo } from "~/component/icon"
import { querySessionInfo, queryBillingInfo, createCheckoutUrl, formatBalance } from "../common" import { querySessionInfo, queryBillingInfo, createCheckoutUrl, formatBalance } from "../common"
import { useI18n } from "~/context/i18n" import { useI18n } from "~/context/i18n"
@@ -73,14 +71,10 @@ export default function () {
<div data-slot="sections"> <div data-slot="sections">
<NewUserSection /> <NewUserSection />
<Show when={userInfo()?.isAdmin}>
<GraphSection />
</Show>
<ModelSection /> <ModelSection />
<Show when={userInfo()?.isAdmin}> <Show when={userInfo()?.isAdmin}>
<ProviderSection /> <ProviderSection />
</Show> </Show>
<UsageSection />
</div> </div>
</div> </div>
) )

View File

@@ -0,0 +1,21 @@
import { Show } from "solid-js"
import { createAsync, useParams } from "@solidjs/router"
import { GraphSection } from "./graph-section"
import { UsageSection } from "./usage-section"
import { querySessionInfo } from "../../common"
export default function () {
const params = useParams()
const user = createAsync(() => querySessionInfo(params.id!))
return (
<div data-page="workspace-[id]">
<div data-slot="sections">
<Show when={user()?.isAdmin}>
<GraphSection />
</Show>
<UsageSection />
</div>
</div>
)
}

View File

@@ -1,7 +1,7 @@
import { Billing } from "@opencode-ai/console-core/billing.js" import { Billing } from "@opencode-ai/console-core/billing.js"
import { createAsync, query, useParams } from "@solidjs/router" import { createAsync, query, useParams } from "@solidjs/router"
import { createMemo, For, Show, Switch, Match, createEffect, createSignal } from "solid-js" import { createMemo, For, Show, Switch, Match, createEffect, createSignal } from "solid-js"
import { formatDateUTC, formatDateForTable } from "../common" import { formatDateUTC, formatDateForTable } from "../../common"
import { withActor } from "~/context/auth.withActor" import { withActor } from "~/context/auth.withActor"
import { IconChevronLeft, IconChevronRight, IconBreakdown } from "~/component/icon" import { IconChevronLeft, IconChevronRight, IconBreakdown } from "~/component/icon"
import styles from "./usage-section.module.css" import styles from "./usage-section.module.css"