mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 22:03:45 +00:00
Add clickable artifact pills to tool renderer
- Create ArtifactPill component (similar to SkillPill) - Renders filename as clickable pill with FileCode2 icon - Clicking pill opens artifacts panel and selects that artifact - Update ArtifactsToolRenderer to accept artifactsPanel reference - Pass artifactsPanel from ChatPanel to renderer on initialization - Display artifact pill below header for all commands - Pill only clickable when artifactsPanel reference is available
This commit is contained in:
parent
b3efac4591
commit
547be7ce37
3 changed files with 50 additions and 6 deletions
|
|
@ -79,7 +79,7 @@ export class ChatPanel extends LitElement {
|
|||
this.artifactsPanel.sandboxUrlProvider = this.sandboxUrlProvider;
|
||||
}
|
||||
// Register the standalone tool renderer (not the panel itself)
|
||||
registerToolRenderer("artifacts", new ArtifactsToolRenderer());
|
||||
registerToolRenderer("artifacts", new ArtifactsToolRenderer(this.artifactsPanel));
|
||||
|
||||
// Attachments provider
|
||||
const getAttachments = () => {
|
||||
|
|
|
|||
23
packages/web-ui/src/tools/artifacts/ArtifactPill.ts
Normal file
23
packages/web-ui/src/tools/artifacts/ArtifactPill.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { html, icon, type TemplateResult } from "@mariozechner/mini-lit";
|
||||
import { FileCode2 } from "lucide";
|
||||
import type { ArtifactsPanel } from "./artifacts.js";
|
||||
|
||||
export function ArtifactPill(filename: string, artifactsPanel?: ArtifactsPanel): TemplateResult {
|
||||
const handleClick = () => {
|
||||
if (!artifactsPanel) return;
|
||||
// openArtifact will show the artifact and call onOpen() to open the panel if needed
|
||||
(artifactsPanel as any).openArtifact(filename);
|
||||
};
|
||||
|
||||
return html`
|
||||
<div
|
||||
class="inline-flex items-center gap-2 px-2 py-1 text-xs bg-muted/50 border border-border rounded ${
|
||||
artifactsPanel ? "cursor-pointer hover:bg-muted transition-colors" : ""
|
||||
}"
|
||||
@click=${artifactsPanel ? handleClick : null}
|
||||
>
|
||||
${icon(FileCode2, "sm")}
|
||||
<span class="font-mono text-foreground">${filename}</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
|
@ -7,7 +7,8 @@ import "../../components/ConsoleBlock.js";
|
|||
import { i18n } from "../../utils/i18n.js";
|
||||
import { renderCollapsibleHeader, renderHeader } from "../renderer-registry.js";
|
||||
import type { ToolRenderer } from "../types.js";
|
||||
import type { ArtifactsParams } from "./artifacts.js";
|
||||
import { ArtifactPill } from "./ArtifactPill.js";
|
||||
import type { ArtifactsPanel, ArtifactsParams } from "./artifacts.js";
|
||||
|
||||
// Helper to determine language for syntax highlighting
|
||||
function getLanguageFromFilename(filename?: string): string {
|
||||
|
|
@ -47,6 +48,8 @@ function getLanguageFromFilename(filename?: string): string {
|
|||
}
|
||||
|
||||
export class ArtifactsToolRenderer implements ToolRenderer<ArtifactsParams, undefined> {
|
||||
constructor(public artifactsPanel?: ArtifactsPanel) {}
|
||||
|
||||
render(
|
||||
params: ArtifactsParams | undefined,
|
||||
result: ToolResultMessage<undefined> | undefined,
|
||||
|
|
@ -71,6 +74,11 @@ export class ArtifactsToolRenderer implements ToolRenderer<ArtifactsParams, unde
|
|||
return labels[command] || { streaming: i18n("Processing artifact"), complete: i18n("Processed artifact") };
|
||||
};
|
||||
|
||||
// Helper to render artifact pill if filename present
|
||||
const renderPill = (filename?: string): TemplateResult | string => {
|
||||
return filename ? ArtifactPill(filename, this.artifactsPanel) : "";
|
||||
};
|
||||
|
||||
// Error handling
|
||||
if (result?.isError) {
|
||||
const command = params?.command;
|
||||
|
|
@ -78,7 +86,7 @@ export class ArtifactsToolRenderer implements ToolRenderer<ArtifactsParams, unde
|
|||
const labels = command
|
||||
? getCommandLabels(command)
|
||||
: { streaming: i18n("Processing artifact"), complete: i18n("Processed artifact") };
|
||||
const headerText = filename ? `${labels.streaming} ${filename}` : labels.streaming;
|
||||
const headerText = labels.streaming;
|
||||
|
||||
// For create/update/rewrite errors, show code block + console/error
|
||||
if (command === "create" || command === "update" || command === "rewrite") {
|
||||
|
|
@ -89,6 +97,7 @@ export class ArtifactsToolRenderer implements ToolRenderer<ArtifactsParams, unde
|
|||
return html`
|
||||
<div>
|
||||
${renderCollapsibleHeader(state, FileCode2, headerText, contentRef, chevronRef, false)}
|
||||
${renderPill(filename) ? html`<div class="mt-2">${renderPill(filename)}</div>` : ""}
|
||||
<div ${ref(contentRef)} class="max-h-0 overflow-hidden transition-all duration-300 space-y-3">
|
||||
${content ? html`<code-block .code=${content} language=${getLanguageFromFilename(filename)}></code-block>` : ""}
|
||||
${
|
||||
|
|
@ -116,7 +125,7 @@ export class ArtifactsToolRenderer implements ToolRenderer<ArtifactsParams, unde
|
|||
const labels = command
|
||||
? getCommandLabels(command)
|
||||
: { streaming: i18n("Processing artifact"), complete: i18n("Processed artifact") };
|
||||
const headerText = filename ? `${labels.complete} ${filename}` : labels.complete;
|
||||
const headerText = labels.complete;
|
||||
|
||||
// GET command: show code block with file content
|
||||
if (command === "get") {
|
||||
|
|
@ -124,6 +133,7 @@ export class ArtifactsToolRenderer implements ToolRenderer<ArtifactsParams, unde
|
|||
return html`
|
||||
<div>
|
||||
${renderCollapsibleHeader(state, FileCode2, headerText, contentRef, chevronRef, false)}
|
||||
${renderPill(filename) ? html`<div class="mt-2">${renderPill(filename)}</div>` : ""}
|
||||
<div ${ref(contentRef)} class="max-h-0 overflow-hidden transition-all duration-300">
|
||||
<code-block .code=${fileContent} language=${getLanguageFromFilename(filename)}></code-block>
|
||||
</div>
|
||||
|
|
@ -137,6 +147,7 @@ export class ArtifactsToolRenderer implements ToolRenderer<ArtifactsParams, unde
|
|||
return html`
|
||||
<div>
|
||||
${renderCollapsibleHeader(state, FileCode2, headerText, contentRef, chevronRef, false)}
|
||||
${renderPill(filename) ? html`<div class="mt-2">${renderPill(filename)}</div>` : ""}
|
||||
<div ${ref(contentRef)} class="max-h-0 overflow-hidden transition-all duration-300">
|
||||
<console-block .content=${logs}></console-block>
|
||||
</div>
|
||||
|
|
@ -153,6 +164,7 @@ export class ArtifactsToolRenderer implements ToolRenderer<ArtifactsParams, unde
|
|||
return html`
|
||||
<div>
|
||||
${renderCollapsibleHeader(state, FileCode2, headerText, contentRef, chevronRef, false)}
|
||||
${renderPill(filename) ? html`<div class="mt-2">${renderPill(filename)}</div>` : ""}
|
||||
<div ${ref(contentRef)} class="max-h-0 overflow-hidden transition-all duration-300 space-y-3">
|
||||
${codeContent ? html`<code-block .code=${codeContent} language=${getLanguageFromFilename(filename)}></code-block>` : ""}
|
||||
${isHtml && logs ? html`<console-block .content=${logs}></console-block>` : ""}
|
||||
|
|
@ -165,6 +177,7 @@ export class ArtifactsToolRenderer implements ToolRenderer<ArtifactsParams, unde
|
|||
return html`
|
||||
<div class="space-y-3">
|
||||
${renderHeader(state, FileCode2, headerText)}
|
||||
${renderPill(filename) ? html`<div class="mt-2">${renderPill(filename)}</div>` : ""}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
|
@ -179,7 +192,7 @@ export class ArtifactsToolRenderer implements ToolRenderer<ArtifactsParams, unde
|
|||
}
|
||||
|
||||
const labels = getCommandLabels(command);
|
||||
const headerText = filename ? `${labels.streaming} ${filename}` : labels.streaming;
|
||||
const headerText = labels.streaming;
|
||||
|
||||
// Render based on command type
|
||||
switch (command) {
|
||||
|
|
@ -188,6 +201,7 @@ export class ArtifactsToolRenderer implements ToolRenderer<ArtifactsParams, unde
|
|||
return html`
|
||||
<div>
|
||||
${renderCollapsibleHeader(state, FileCode2, headerText, contentRef, chevronRef, false)}
|
||||
${renderPill(filename) ? html`<div class="mt-2">${renderPill(filename)}</div>` : ""}
|
||||
<div ${ref(contentRef)} class="max-h-0 overflow-hidden transition-all duration-300">
|
||||
${
|
||||
content
|
||||
|
|
@ -202,6 +216,7 @@ export class ArtifactsToolRenderer implements ToolRenderer<ArtifactsParams, unde
|
|||
return html`
|
||||
<div>
|
||||
${renderCollapsibleHeader(state, FileCode2, headerText, contentRef, chevronRef, false)}
|
||||
${renderPill(filename) ? html`<div class="mt-2">${renderPill(filename)}</div>` : ""}
|
||||
<div ${ref(contentRef)} class="max-h-0 overflow-hidden transition-all duration-300">
|
||||
${
|
||||
old_str !== undefined && new_str !== undefined
|
||||
|
|
@ -217,13 +232,19 @@ export class ArtifactsToolRenderer implements ToolRenderer<ArtifactsParams, unde
|
|||
return html`
|
||||
<div>
|
||||
${renderCollapsibleHeader(state, FileCode2, headerText, contentRef, chevronRef, false)}
|
||||
${renderPill(filename) ? html`<div class="mt-2">${renderPill(filename)}</div>` : ""}
|
||||
<div ${ref(contentRef)} class="max-h-0 overflow-hidden transition-all duration-300"></div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
case "delete":
|
||||
default:
|
||||
return renderHeader(state, FileCode2, headerText);
|
||||
return html`
|
||||
<div>
|
||||
${renderHeader(state, FileCode2, headerText)}
|
||||
${renderPill(filename) ? html`<div class="mt-2">${renderPill(filename)}</div>` : ""}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue