mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-20 02:03:16 +00:00
Fix HtmlArtifacts no loading/updating
This commit is contained in:
parent
79dd23b6da
commit
6d046236bf
10 changed files with 2289 additions and 97 deletions
|
|
@ -56,36 +56,42 @@ export class HtmlArtifact extends ArtifactElement {
|
|||
const oldValue = this._content;
|
||||
this._content = value;
|
||||
if (oldValue !== value) {
|
||||
// Reset logs when content changes
|
||||
this.logs = [];
|
||||
if (this.consoleLogsRef.value) {
|
||||
this.consoleLogsRef.value.innerHTML = "";
|
||||
}
|
||||
this.requestUpdate();
|
||||
// Execute content in sandbox if it exists
|
||||
if (this.sandboxIframeRef.value && value) {
|
||||
this.logs = [];
|
||||
if (this.consoleLogsRef.value) {
|
||||
this.consoleLogsRef.value.innerHTML = "";
|
||||
}
|
||||
this.updateConsoleButton();
|
||||
this.executeContent(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async executeContent(html: string) {
|
||||
private executeContent(html: string) {
|
||||
const sandbox = this.sandboxIframeRef.value;
|
||||
if (!sandbox) return;
|
||||
|
||||
try {
|
||||
const sandboxId = `artifact-${Date.now()}`;
|
||||
const result = await sandbox.execute(sandboxId, html, this.attachments);
|
||||
const sandboxId = `artifact-${this.filename}`;
|
||||
|
||||
// Update logs with proper type casting
|
||||
this.logs = (result.console || []).map((log) => ({
|
||||
type: log.type === "error" ? ("error" as const) : ("log" as const),
|
||||
text: log.text,
|
||||
}));
|
||||
this.updateConsoleButton();
|
||||
} catch (error) {
|
||||
console.error("HTML artifact execution failed:", error);
|
||||
}
|
||||
// Set up message listener to collect logs
|
||||
const messageHandler = (e: MessageEvent) => {
|
||||
if (e.data.sandboxId !== sandboxId) return;
|
||||
|
||||
if (e.data.type === "console") {
|
||||
this.logs.push({
|
||||
type: e.data.method === "error" ? "error" : "log",
|
||||
text: e.data.text,
|
||||
});
|
||||
this.updateConsoleButton();
|
||||
}
|
||||
};
|
||||
window.addEventListener("message", messageHandler);
|
||||
|
||||
// Load content (iframe persists, doesn't get removed)
|
||||
sandbox.loadContent(sandboxId, html, this.attachments);
|
||||
}
|
||||
|
||||
override get content(): string {
|
||||
|
|
@ -99,6 +105,15 @@ export class HtmlArtifact extends ArtifactElement {
|
|||
}
|
||||
}
|
||||
|
||||
override updated(changedProperties: Map<string | number | symbol, unknown>) {
|
||||
super.updated(changedProperties);
|
||||
// If we have content but haven't executed yet (e.g., during reconstruction),
|
||||
// execute when the iframe ref becomes available
|
||||
if (this._content && this.sandboxIframeRef.value && this.logs.length === 0) {
|
||||
this.executeContent(this._content);
|
||||
}
|
||||
}
|
||||
|
||||
private updateConsoleButton() {
|
||||
const button = this.consoleButtonRef.value;
|
||||
if (!button) return;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Badge, Button, Diff, icon } from "@mariozechner/mini-lit";
|
||||
import { Button, Diff, icon } from "@mariozechner/mini-lit";
|
||||
import { type AgentTool, type Message, StringEnum, type ToolCall, type ToolResultMessage } from "@mariozechner/pi-ai";
|
||||
import { type Static, Type } from "@sinclair/typebox";
|
||||
import { html, LitElement, type TemplateResult } from "lit";
|
||||
|
|
@ -166,13 +166,17 @@ export class ArtifactsPanel extends LitElement implements ToolRenderer<Artifacts
|
|||
// Store element
|
||||
this.artifactElements.set(filename, element);
|
||||
|
||||
// Add to DOM after next render
|
||||
// Add to DOM - try immediately if container exists, otherwise schedule
|
||||
const newElement = element;
|
||||
requestAnimationFrame(() => {
|
||||
if (this.contentRef.value && !newElement.parentElement) {
|
||||
this.contentRef.value.appendChild(newElement);
|
||||
}
|
||||
});
|
||||
if (this.contentRef.value) {
|
||||
this.contentRef.value.appendChild(newElement);
|
||||
} else {
|
||||
requestAnimationFrame(() => {
|
||||
if (this.contentRef.value && !newElement.parentElement) {
|
||||
this.contentRef.value.appendChild(newElement);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Just update content
|
||||
element.content = content;
|
||||
|
|
@ -820,46 +824,19 @@ CRITICAL REMINDER FOR ALL ARTIFACTS:
|
|||
override render(): TemplateResult {
|
||||
const artifacts = Array.from(this._artifacts.values());
|
||||
|
||||
const showContainer = artifacts.length > 0 && !this.collapsed;
|
||||
// Panel is hidden when collapsed OR when there are no artifacts
|
||||
const showPanel = artifacts.length > 0 && !this.collapsed;
|
||||
|
||||
return html`
|
||||
<!-- Floating reopen pill when collapsed and artifacts exist -->
|
||||
${
|
||||
this.collapsed && artifacts.length > 0
|
||||
? html`
|
||||
<button
|
||||
class="absolute z-30 top-4 left-1/2 -translate-x-1/2 pointer-events-auto"
|
||||
@click=${() => this.onOpen?.()}
|
||||
title=${i18n("Show artifacts")}
|
||||
>
|
||||
${Badge(html`
|
||||
<span class="inline-flex items-center gap-1">
|
||||
<span>${i18n("Artifacts")}</span>
|
||||
${
|
||||
artifacts.length > 1
|
||||
? html`<span
|
||||
class="text-[10px] leading-none bg-primary-foreground/20 text-primary-foreground rounded px-1 font-mono tabular-nums"
|
||||
>${artifacts.length}</span
|
||||
>`
|
||||
: ""
|
||||
}
|
||||
</span>
|
||||
`)}
|
||||
</button>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
|
||||
<!-- Panel container -->
|
||||
<div
|
||||
class="${showContainer ? "" : "hidden"} ${
|
||||
class="${showPanel ? "" : "hidden"} ${
|
||||
this.overlay ? "fixed inset-0 z-40 pointer-events-auto backdrop-blur-sm bg-background/95" : "relative"
|
||||
} h-full flex flex-col bg-card text-card-foreground ${
|
||||
} h-full flex flex-col bg-background text-card-foreground ${
|
||||
!this.overlay ? "border-l border-border" : ""
|
||||
} overflow-hidden shadow-xl"
|
||||
>
|
||||
<!-- Tab bar (always shown when there are artifacts) -->
|
||||
<div class="flex items-center justify-between border-b border-border bg-muted/30">
|
||||
<div class="flex items-center justify-between border-b border-border bg-background">
|
||||
<div class="flex overflow-x-auto">
|
||||
${artifacts.map((a) => {
|
||||
const isActive = a.filename === this._activeFilename;
|
||||
|
|
@ -868,10 +845,10 @@ CRITICAL REMINDER FOR ALL ARTIFACTS:
|
|||
: "border-transparent text-muted-foreground hover:text-foreground";
|
||||
return html`
|
||||
<button
|
||||
class="px-3 py-2 text-sm whitespace-nowrap border-b-2 ${activeClass}"
|
||||
class="px-3 py-2 whitespace-nowrap border-b-2 ${activeClass}"
|
||||
@click=${() => this.showArtifact(a.filename)}
|
||||
>
|
||||
<span class="font-mono">${a.filename}</span>
|
||||
<span class="font-mono text-xs">${a.filename}</span>
|
||||
</button>
|
||||
`;
|
||||
})}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue