feat(ui): move context usage pills to right drawer header
This commit is contained in:
@@ -923,7 +923,6 @@ const InstanceShell2: Component<InstanceShellProps> = (props) => {
|
|||||||
<Show when={activeSessionForInstance()}>
|
<Show when={activeSessionForInstance()}>
|
||||||
{(activeSession) => (
|
{(activeSession) => (
|
||||||
<>
|
<>
|
||||||
<ContextUsagePanel instanceId={props.instance.id} sessionId={activeSession().id} />
|
|
||||||
<div class="session-sidebar-controls px-4 py-4 border-t border-base flex flex-col gap-3">
|
<div class="session-sidebar-controls px-4 py-4 border-t border-base flex flex-col gap-3">
|
||||||
<AgentSelector
|
<AgentSelector
|
||||||
instanceId={props.instance.id}
|
instanceId={props.instance.id}
|
||||||
@@ -1091,35 +1090,46 @@ const InstanceShell2: Component<InstanceShellProps> = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="flex flex-col h-full" ref={setRightDrawerContentEl}>
|
<div class="flex flex-col h-full" ref={setRightDrawerContentEl}>
|
||||||
<div class="relative flex items-center px-4 py-2 border-b border-base text-primary">
|
<div class="border-b border-base text-primary">
|
||||||
<div class="flex items-center gap-2">
|
<div class="relative flex items-center px-4 py-2">
|
||||||
<Show when={rightDrawerState() === "floating-open"}>
|
<div class="flex items-center gap-2">
|
||||||
<IconButton
|
<Show when={rightDrawerState() === "floating-open"}>
|
||||||
size="small"
|
<IconButton
|
||||||
color="inherit"
|
size="small"
|
||||||
aria-label={t("instanceShell.rightDrawer.toggle.close")}
|
color="inherit"
|
||||||
title={t("instanceShell.rightDrawer.toggle.close")}
|
aria-label={t("instanceShell.rightDrawer.toggle.close")}
|
||||||
onClick={closeRightDrawer}
|
title={t("instanceShell.rightDrawer.toggle.close")}
|
||||||
>
|
onClick={closeRightDrawer}
|
||||||
<MenuOpenIcon fontSize="small" sx={{ transform: "scaleX(-1)" }} />
|
>
|
||||||
</IconButton>
|
<MenuOpenIcon fontSize="small" sx={{ transform: "scaleX(-1)" }} />
|
||||||
</Show>
|
</IconButton>
|
||||||
<Show when={!isPhoneLayout()}>
|
</Show>
|
||||||
<IconButton
|
<Show when={!isPhoneLayout()}>
|
||||||
size="small"
|
<IconButton
|
||||||
color="inherit"
|
size="small"
|
||||||
aria-label={rightPinned() ? t("instanceShell.rightDrawer.unpin") : t("instanceShell.rightDrawer.pin")}
|
color="inherit"
|
||||||
onClick={() => (rightPinned() ? unpinRightDrawer() : pinRightDrawer())}
|
aria-label={rightPinned() ? t("instanceShell.rightDrawer.unpin") : t("instanceShell.rightDrawer.pin")}
|
||||||
>
|
onClick={() => (rightPinned() ? unpinRightDrawer() : pinRightDrawer())}
|
||||||
{rightPinned() ? <PushPinIcon fontSize="small" /> : <PushPinOutlinedIcon fontSize="small" />}
|
>
|
||||||
</IconButton>
|
{rightPinned() ? <PushPinIcon fontSize="small" /> : <PushPinOutlinedIcon fontSize="small" />}
|
||||||
</Show>
|
</IconButton>
|
||||||
</div>
|
</Show>
|
||||||
<div class="pointer-events-none absolute inset-0 flex items-center justify-center">
|
</div>
|
||||||
<Typography variant="subtitle2" class="uppercase tracking-wide text-xs font-semibold text-primary">
|
<div class="pointer-events-none absolute inset-0 flex items-center justify-center">
|
||||||
{t("instanceShell.rightPanel.title")}
|
<span class="session-sidebar-title text-sm font-semibold uppercase text-primary">
|
||||||
</Typography>
|
{t("instanceShell.rightPanel.title")}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<Show when={activeSessionForInstance()}>
|
||||||
|
{(activeSession) => (
|
||||||
|
<ContextUsagePanel
|
||||||
|
instanceId={props.instance.id}
|
||||||
|
sessionId={activeSession().id}
|
||||||
|
class="border-t border-base"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-1 overflow-y-auto">
|
<div class="flex-1 overflow-y-auto">
|
||||||
<Accordion.Root
|
<Accordion.Root
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ import { useI18n } from "../../lib/i18n"
|
|||||||
interface ContextUsagePanelProps {
|
interface ContextUsagePanelProps {
|
||||||
instanceId: string
|
instanceId: string
|
||||||
sessionId: string
|
sessionId: string
|
||||||
|
class?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const chipClass = "inline-flex items-center gap-1 rounded-full border border-base px-2 py-0.5 text-xs text-primary"
|
const chipClass = "inline-flex items-center gap-1 rounded-full border border-base px-2 py-0.5 text-xs text-primary"
|
||||||
const chipLabelClass = "uppercase text-[10px] tracking-wide text-muted"
|
const chipLabelClass = "uppercase text-[10px] tracking-wide text-muted"
|
||||||
const headingClass = "text-xs font-semibold text-muted uppercase tracking-wide"
|
|
||||||
|
|
||||||
const ContextUsagePanel: Component<ContextUsagePanelProps> = (props) => {
|
const ContextUsagePanel: Component<ContextUsagePanelProps> = (props) => {
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
@@ -31,26 +31,16 @@ const ContextUsagePanel: Component<ContextUsagePanelProps> = (props) => {
|
|||||||
|
|
||||||
const inputTokens = createMemo(() => info().inputTokens ?? 0)
|
const inputTokens = createMemo(() => info().inputTokens ?? 0)
|
||||||
const outputTokens = createMemo(() => info().outputTokens ?? 0)
|
const outputTokens = createMemo(() => info().outputTokens ?? 0)
|
||||||
const actualUsageTokens = createMemo(() => info().actualUsageTokens ?? 0)
|
|
||||||
const availableTokens = createMemo(() => info().contextAvailableTokens)
|
|
||||||
const outputLimit = createMemo(() => info().modelOutputLimit ?? 0)
|
|
||||||
const costValue = createMemo(() => {
|
const costValue = createMemo(() => {
|
||||||
const value = info().isSubscriptionModel ? 0 : info().cost
|
const value = info().isSubscriptionModel ? 0 : info().cost
|
||||||
return value > 0 ? value : 0
|
return value > 0 ? value : 0
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
const formatTokenValue = (value: number | null | undefined) => {
|
|
||||||
if (value === null || value === undefined) return t("contextUsagePanel.unavailable")
|
|
||||||
return formatTokenTotal(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const costDisplay = createMemo(() => `$${costValue().toFixed(2)}`)
|
const costDisplay = createMemo(() => `$${costValue().toFixed(2)}`)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="session-context-panel border-r border-base border-b px-3 py-3 space-y-3">
|
<div class={`session-context-panel px-4 py-2 ${props.class ?? ""}`}>
|
||||||
<div class="flex flex-wrap items-center gap-2 text-xs text-primary">
|
<div class="flex flex-wrap items-center gap-2 text-xs text-primary">
|
||||||
<div class={headingClass}>{t("contextUsagePanel.headings.tokens")}</div>
|
|
||||||
<div class={chipClass}>
|
<div class={chipClass}>
|
||||||
<span class={chipLabelClass}>{t("contextUsagePanel.labels.input")}</span>
|
<span class={chipLabelClass}>{t("contextUsagePanel.labels.input")}</span>
|
||||||
<span class="font-semibold text-primary">{formatTokenTotal(inputTokens())}</span>
|
<span class="font-semibold text-primary">{formatTokenTotal(inputTokens())}</span>
|
||||||
@@ -64,18 +54,6 @@ const ContextUsagePanel: Component<ContextUsagePanelProps> = (props) => {
|
|||||||
<span class="font-semibold text-primary">{costDisplay()}</span>
|
<span class="font-semibold text-primary">{costDisplay()}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-wrap items-center gap-2 text-xs text-primary">
|
|
||||||
<div class={headingClass}>{t("contextUsagePanel.headings.context")}</div>
|
|
||||||
<div class={chipClass}>
|
|
||||||
<span class={chipLabelClass}>{t("contextUsagePanel.labels.used")}</span>
|
|
||||||
<span class="font-semibold text-primary">{formatTokenTotal(actualUsageTokens())}</span>
|
|
||||||
</div>
|
|
||||||
<div class={chipClass}>
|
|
||||||
<span class={chipLabelClass}>{t("contextUsagePanel.labels.available")}</span>
|
|
||||||
<span class="font-semibold text-primary">{formatTokenValue(availableTokens())}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user