blob: c6aa81104621ac77a6891c81f64dce2e92e9a43d [file] [log] [blame]
import { State } from "../types";
import { LitElement, css, html } from "lit";
import { customElement, property } from "lit/decorators.js";
@customElement("sketch-container-status")
export class SketchContainerStatus extends LitElement {
// Header bar: Container status details
@property()
state: State;
// See https://lit.dev/docs/components/styles/ for how lit-element handles CSS.
// Note that these styles only apply to the scope of this web component's
// shadow DOM node, so they won't leak out or collide with CSS declared in
// other components or the containing web page (...unless you want it to do that).
static styles = css`
.info-card {
background: #f9f9f9;
border-radius: 8px;
padding: 15px;
margin-bottom: 20px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
display: none; /* Hidden in the combined layout */
}
.info-grid {
display: flex;
flex-wrap: wrap;
gap: 8px;
background: #f9f9f9;
border-radius: 4px;
padding: 4px 10px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
flex: 1;
}
.info-item {
display: flex;
align-items: center;
white-space: nowrap;
margin-right: 10px;
font-size: 13px;
}
.info-label {
font-size: 11px;
color: #555;
margin-right: 3px;
font-weight: 500;
}
.info-value {
font-size: 11px;
font-weight: 600;
}
[title] {
cursor: help;
text-decoration: underline dotted;
}
.cost {
color: #2e7d32;
}
.info-item a {
--tw-text-opacity: 1;
color: rgb(37 99 235 / var(--tw-text-opacity, 1));
text-decoration: inherit;
}
`;
constructor() {
super();
}
formatHostname() {
const hostHostname = this.state?.host_hostname;
const runtimeHostname = this.state?.runtime_hostname;
if (!hostHostname || !runtimeHostname) {
return this.state?.hostname;
}
if (hostHostname === runtimeHostname) {
return hostHostname;
}
return `${hostHostname}:${runtimeHostname}`;
}
formatWorkingDir() {
const hostWorkingDir = this.state?.host_working_dir;
const runtimeWorkingDir = this.state?.runtime_working_dir;
if (!hostWorkingDir || !runtimeWorkingDir) {
return this.state?.working_dir;
}
if (hostWorkingDir === runtimeWorkingDir) {
return hostWorkingDir;
}
return `${hostWorkingDir}:${runtimeWorkingDir}`;
}
getHostnameTooltip() {
const hostHostname = this.state?.host_hostname;
const runtimeHostname = this.state?.runtime_hostname;
if (!hostHostname || !runtimeHostname || hostHostname === runtimeHostname) {
return "";
}
return `Host: ${hostHostname}, Runtime: ${runtimeHostname}`;
}
getWorkingDirTooltip() {
const hostWorkingDir = this.state?.host_working_dir;
const runtimeWorkingDir = this.state?.runtime_working_dir;
if (
!hostWorkingDir ||
!runtimeWorkingDir ||
hostWorkingDir === runtimeWorkingDir
) {
return "";
}
return `Host: ${hostWorkingDir}, Runtime: ${runtimeWorkingDir}`;
}
// See https://lit.dev/docs/components/lifecycle/
connectedCallback() {
super.connectedCallback();
// register event listeners
}
// See https://lit.dev/docs/components/lifecycle/
disconnectedCallback() {
super.disconnectedCallback();
// unregister event listeners
}
render() {
return html`
<div class="info-grid">
<div class="info-item">
<a href="logs">Logs</a>
</div>
<div class="info-item">
<a href="download">Download</a>
</div>
<div class="info-item">
<span
id="hostname"
class="info-value"
title="${this.getHostnameTooltip()}"
>
${this.formatHostname()}
</span>
</div>
<div class="info-item">
<span
id="workingDir"
class="info-value"
title="${this.getWorkingDirTooltip()}"
>
${this.formatWorkingDir()}
</span>
</div>
${this.state?.git_origin
? html`
<div class="info-item">
<span class="info-label">Origin:</span>
<span id="gitOrigin" class="info-value"
>${this.state?.git_origin}</span
>
</div>
`
: ""}
<div class="info-item">
<span class="info-label">Commit:</span>
<span id="initialCommit" class="info-value"
>${this.state?.initial_commit?.substring(0, 8)}</span
>
</div>
<div class="info-item">
<span class="info-label">Msgs:</span>
<span id="messageCount" class="info-value"
>${this.state?.message_count}</span
>
</div>
<div class="info-item">
<span class="info-label">In:</span>
<span id="inputTokens" class="info-value"
>${this.state?.total_usage?.input_tokens}</span
>
</div>
<div class="info-item">
<span class="info-label">Cache Read:</span>
<span id="cacheReadInputTokens" class="info-value"
>${this.state?.total_usage?.cache_read_input_tokens}</span
>
</div>
<div class="info-item">
<span class="info-label">Cache Create:</span>
<span id="cacheCreationInputTokens" class="info-value"
>${this.state?.total_usage?.cache_creation_input_tokens}</span
>
</div>
<div class="info-item">
<span class="info-label">Out:</span>
<span id="outputTokens" class="info-value"
>${this.state?.total_usage?.output_tokens}</span
>
</div>
<div class="info-item">
<span class="info-label">Cost:</span>
<span id="totalCost" class="info-value cost"
>$${(this.state?.total_usage?.total_cost_usd || 0).toFixed(2)}</span
>
</div>
</div>
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"sketch-container-status": SketchContainerStatus;
}
}