Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .devcontainer/devcontainer-lock.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"features": {
"ghcr.io/devcontainer-community/devcontainer-features/bun.sh:1": {
"version": "1.0.2",
"resolved": "ghcr.io/devcontainer-community/devcontainer-features/bun.sh@sha256:97e64946087b8519097510fbef5c66dfcd6cd8e7ac3bbee9638ba8e60fea5918",
"integrity": "sha256:97e64946087b8519097510fbef5c66dfcd6cd8e7ac3bbee9638ba8e60fea5918"
},
"ghcr.io/devcontainers/features/python:1": {
"version": "1.8.0",
"resolved": "ghcr.io/devcontainers/features/python@sha256:fbcad6955caeecc5ad3f7886baf652e25cba5225a6c4c2287c536de2e5607511",
"integrity": "sha256:fbcad6955caeecc5ad3f7886baf652e25cba5225a6c4c2287c536de2e5607511"
}
}
}
26 changes: 26 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/universal
{
"name": "Default Linux Universal",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
"ghcr.io/devcontainer-community/devcontainer-features/bun.sh:1": {},
"ghcr.io/devcontainers/features/python:1": {}
}

// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},

// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],

// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "uname -a",

// Configure tool-specific properties.
// "customizations": {},

// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}
3 changes: 2 additions & 1 deletion packages/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"start": "astro dev",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
"astro": "astro",
"test": "bun test"
},
"dependencies": {
"@astrojs/cloudflare": "12.6.3",
Expand Down
23 changes: 15 additions & 8 deletions packages/web/src/components/share/part.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
IconCommandLine,
IconCheckCircle,
IconChevronDown,
IconChevronRight,
IconDocumentPlus,
IconPencilSquare,
IconRectangleStack,
Expand Down Expand Up @@ -41,9 +40,17 @@ export interface PartProps {
last: boolean
}

export function getCompletedAt(props: Pick<PartProps, "last" | "message">): number | undefined {
if (props.last && props.message.role === "assistant" && props.message.time.completed){
return props.message.time.completed
}
return undefined
}

export function Part(props: PartProps) {
const [copied, setCopied] = createSignal(false)
const id = createMemo(() => props.message.id + "-" + props.index)
const completedAt = createMemo(() => getCompletedAt(props))
const messages = useShareMessages()

return (
Expand Down Expand Up @@ -139,15 +146,15 @@ export function Part(props: PartProps) {
<div data-component="assistant-text-markdown">
<ContentMarkdown expand={props.last} text={props.part.text} />
</div>
{props.last && props.message.role === "assistant" && props.message.time.completed && (
{completedAt() !== undefined && (
<Footer
title={DateTime.fromMillis(props.message.time.completed)
.setLocale(normalizeLocale(messages.locale))
.toLocaleString(DateTime.DATETIME_FULL_WITH_SECONDS)}
title= {DateTime.fromMillis(completedAt()!)
.setLocale(normalizeLocale(messages.locale))
.toLocaleString(DateTime.DATETIME_FULL_WITH_SECONDS)}
>
{DateTime.fromMillis(props.message.time.completed)
.setLocale(normalizeLocale(messages.locale))
.toLocaleString(DateTime.DATETIME_MED)}
{DateTime.fromMillis(completedAt()!)
.setLocale(normalizeLocale(messages.locale))
.toLocaleString(DateTime.DATETIME_MED)}
</Footer>
)}
</div>
Expand Down
36 changes: 36 additions & 0 deletions packages/web/test/part.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { test, expect } from "bun:test"
import { getCompletedAt } from "../src/components/share/part"
import type { MessageV2 } from "opencode/session/message-v2"

function assistantMessage(overrides: Partial<{ completed: number }> = {}): MessageV2.Info {
return {
role: "assistant",
time: { completed: overrides.completed },
} as unknown as MessageV2.Info
}

function userMessage(): MessageV2.Info {
return {
role: "user",
} as unknown as MessageV2.Info
}

test("returns completed time when last, assistant, and completed is set", () => {
const message = assistantMessage({ completed: 1234567890 })
expect(getCompletedAt({ last: true, message })).toBe(1234567890)
})

test("returns undefined when not the last part", () => {
const message = assistantMessage({ completed: 1234567890 })
expect(getCompletedAt({ last: false, message })).toBeUndefined()
})

test("returns undefined when message role is user", () => {
const message = userMessage()
expect(getCompletedAt({ last: true, message })).toBeUndefined()
})

test("returns undefined when assistant message has no completed time", () => {
const message = assistantMessage()
expect(getCompletedAt({ last: true, message })).toBeUndefined()
})
4 changes: 4 additions & 0 deletions turbo.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@
"@opencode-ai/session-ui#test": {
"dependsOn": ["^build"],
"outputs": []
},
"@opencode-ai/web#test": {
"dependsOn": ["^build"],
"outputs": []
}
}
}
Loading